Вопрос

У меня есть следующий надувший пример (исходя из реального кода):

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 и Boost :: 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 типа, полученного1* указывает на полученное2?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top