Question

Je l'exemple suivant artificiel (provenant du code réel):

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);
}

Quand je tente de compiler, je reçois:

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) Il est clair que gcc est se confondre par les constructeurs. Si je supprime la référence des constructeurs, le code compile. Donc, mon hypothèse est que quelque chose va mal avec des références de pointeur vers le haut-casting. Quelqu'un peut-il me dire ce qui se passe ici?

2) Une question légèrement sans rapport. Si je devais faire quelque chose comme horrible « supprimer d'autres » dans le constructeur (ours avec moi), ce qui se passe quand quelqu'un me passe un pointeur vers quelque chose sur la pile?

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

where 

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

Comment puis-je faire en sorte que le pointeur pointe légitimement à quelque chose sur le tas?

Était-ce utile?

La solution

Base<T> est un type de base de Derived<T>, mais Base<T>* est pas un type de base de Derived<T>*. Vous pouvez passer un pointeur dérivé en place d'un pointeur de base, mais vous ne pouvez pas passer une référence de pointeur dérivé en place d'une référence de pointeur base.

La raison en est que, supposons que vous pourriez, et supposons que le constructeur de base devaient écrire une valeur dans la référence:

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

Vous venez d'écrire un pointeur vers quelque chose qui est pas un Derived<T>, en un pointeur vers Derived<T>. Le compilateur ne peut pas laisser cela se produire.

Autres conseils

  1. Vous ne pouvez pas convertir une référence à un pointeur vers dérivé d'une référence à un pointeur vers la base. (Les modèles ne contribuent pas à la question ici, donc retiré de mon exemple ci-dessous.)
  2. Si vous voulez reporter la responsabilité d'un pointeur, utilisez un type de pointeur intelligent. types de pointeurs intelligents peuvent représenter la « responsabilité de supprimer » que les pointeurs premières ne peuvent pas. Les exemples incluent std :: auto_ptr et boost :: shared_ptr , entre beaucoup d'autres.

Pourquoi vous ne pouvez pas transtyper références pointeur:

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!
}

Lorsque vous passez votre paramètre « autre » à la cteur de base, vous essayez de faire la même chose que b_ptr = d_ptr ci-dessus.

Vous assurez-vous que les points de pointeur à quelque chose sur le tas par écrit que dans la documentation et se fondant sur l'appelant à respecter cela. Si quiconque invoquera votre constructeur passe un pointeur de pile, tous les paris sont ouverts, et ce n'est pas votre faute - vous pouvez essayer de prendre le problème au début, mais aucune garantie

.

Voilà comment fonctionne la bibliothèque standard -. Souvent il va attraper des erreurs évidentes, mais il n'est pas nécessaire, et il est à l'appelant pour vous assurer qu'ils ne font rien de stupide

Votre variable x n'est pas un pointeur, il devrait être si vous souhaitez attribuer un new Derived<int> à lui.

En ce qui concerne la suppression des choses sur la pile, ne le font pas. Il n'y a pas moyen de savoir si vous avez passé l'adresse de quelque chose sur la pile ou sur le tas (en effet, la norme C de ne reconnaît même pas l'existence d'une pile). La leçon ici est que vous ne devriez pas les choses que vous supprimez ne possédez pas, surtout si vous avez aucun moyen de savoir d'où ils venaient.

Je ne sais pas pourquoi voulez-vous référence au pointeur. Pourquoi ne pas

Base(Base<T> * other) { }

et

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

Cela devrait fonctionner.

Et, comme d'autres ont répondu, je ne pense pas que vous pouvez savoir si légitimement le pointeur pointe en tas.

Modifier : pourquoi ne peut-on faire ce que vous essayez de: considérer par exemple:

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

Où Derived1 et Derived2 sont différentes classes dérivées de base? Pensez-vous qu'il est légitime? Maintenant que x de type Derived1 * points Derived2?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top