문제

다음과 같은 예제가 있습니다 (실제 코드에서 나옵니다).

template <class T>
class Base {
public:
 Base(int a):x(a) {}
    Base(Base<T> * &other) { }
    virtual ~Base() {}
private:
 int x;
};

template <class T>
class Derived:public Base<T>{
public:
  Derived(int x):Base<T>(x) {}
  Derived(Derived<T>* &other): Base<T>(other) {}

};


int main() {
 Derived<int> *x=new Derived<int>(1);
 Derived<int> y(x);
}

이것을 컴파일하려고 할 때 : 나는 다음을 얻는다.

1X.cc: In constructor ‘Derived<T>::Derived(Derived<T>*&) [with T = int]’:
1X.cc:27:   instantiated from here
1X.cc:20: error: invalid conversion from ‘Derived<int>*’ to ‘int’
1X.cc:20: error:   initializing argument 1 of ‘Base<T>::Base(int) [with T = int]’

1) 분명히 GCC는 생성자에 의해 혼란스러워지고 있습니다. 생성자에서 기준을 제거하면 코드가 컴파일됩니다. 그래서 내 가정은 업 캐스트 포인터 참조로 문제가 발생한다는 것입니다. 누군가 여기서 무슨 일이 일어나고 있는지 말해 줄 수 있습니까?

2) 약간 관련이없는 질문. 제작자에서 "다른 사람 삭제"와 같은 끔찍한 일을한다면 (나와 함께) 누군가 나에게 스택에서 무언가에 대한 포인터를 전달하면 어떻게됩니까?

E.g. Derived<int> x(2);
     Derived<int> y(x);

where 

 Derived(Derived<T>*& other) { delete other;}

포인터가 힙에 무언가를 합법적으로 가리키고 있는지 어떻게 지적 할 수 있습니까?

도움이 되었습니까?

해결책

Base<T> 기본 유형입니다 Derived<T>, 하지만 Base<T>* 기본 유형이 아닙니다 Derived<T>*. 베이스 포인터 대신 파생 포인터를 전달할 수 있지만베이스 포인터 참조 대신 파생 된 포인터 참조를 전달할 수는 없습니다.

그 이유는, 당신이 할 수 있다고 가정하고,베이스의 생성자가 참조에 약간의 가치를 써야한다고 가정하기 때문입니다.

Base(Base<T> * &other) {
    Base<T> *thing = new Base<T>(12);
    other = thing;
}

당신은 방금 무언가에 대한 포인터를 썼습니다 ~ 아니다Derived<T>, 포인터로 Derived<T>. 컴파일러는 이런 일이 일어날 수 없습니다.

다른 팁

  1. 포인터에 대한 참조를 기준으로 변환 할 수는 없습니다. (템플릿은 여기서 문제에 기여하지 않으므로 아래의 예에서 제거되었습니다.)
  2. 포인터에 대한 책임을 연기하려면 스마트 포인터 유형을 사용하십시오. 스마트 포인터 유형은 원시 포인터가 할 수없는 "삭제에 대한 책임"을 나타낼 수 있습니다. 예제는 std :: auto_ptr 및입니다 부스트 :: shared_ptr, 많은 것 중에서도.

포인터 참조를 올릴 수없는 이유 :

struct Base {};
struct Derived : Base {};
struct Subclass : Base {};

int main() {
  Derived d;
  Derived* p = &d;
  Derived*& d_ptr = p;

  Base*& b_ptr = d_ptr; // this is not allowed, but let's say it is

  Base b;
  b_ptr = &b; // oops! d_ptr no longer points to a Derived!

  Subclass s;
  b_ptr = &s; // oops! d_ptr no longer points to a Derived!
}

'기타'매개 변수를 기본 CTOR에 전달하면 다음과 같은 작업을 수행하려고합니다. b_ptr = d_ptr 위에.

포인터가 문서에 글을 쓰고 발신자에게 의존하여 포인터가 힙에 무언가를 가리키도록합니다. 생성자가 스택 포인터를 통과하는 사람이라면 모든 베팅이 꺼져 있고 잘못이 아닙니다. 문제를 조기에 잡을 수는 있지만 보장은 없습니다.

그것이 표준 라이브러리가 작동하는 방식입니다. 종종 명백한 오류가 발생하지만 필요하지는 않지만 발신자에게 어리석은 일을하지 않도록하는 것은 발신자에게 달려 있습니다.

당신의 x 변수는 포인터가 아니므로 할당하려면 이루어져야합니다. new Derived<int> 그것에.

스택에서 물건을 삭제하는 것은하지 마십시오. 스택이나 힙에 무언가의 주소를 통과했는지 여부를 알 수있는 방법은 없습니다 (실제로 C ++ 표준은 스택의 존재를 인정하지 않습니다). 여기서 교훈은 당신이 소유하지 않은 것을 삭제해서는 안된다는 것입니다. 특히 그들이 어디에서 왔는지 알 수있는 방법이 없다면.

왜 포인터에 대한 참조를 원하는지 잘 모르겠습니다. 왜 안 돼

Base(Base<T> * other) { }

그리고

Derived(Derived<T>* other): Base<T>(other) {}

작동해야합니다.

그리고 다른 대답과 마찬가지로, 나는 당신이 포인터가 힙을 가리키는 지 합법적으로 알 수 없다고 생각합니다.

편집하다: 왜 당신이하려는 일을 할 수없는 이유 : 예를 고려하십시오 :

Derived1<int> *x = new Derived1<int>
Base<int> **xx =&x;
Derived2<int> y;
*xx = &y;

여기서 파생 된 1과 파생물 2가 있습니다 다른 기지에서 파생 된 수업? 합법적이라고 생각하십니까? 이제 유형의 X가 파생 된 2를 가리 킵니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top