Domanda

Ho il seguente esempio forzato (proveniente dal codice vero e proprio):

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

Quando provo a compilare questo, ottengo:

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) Chiaramente gcc viene confuso dai costruttori. Se rimuovo il riferimento dai costruttori, allora il codice viene compilato. Quindi la mia ipotesi è che qualcosa va storto con i riferimenti di puntatore up-fusione. Qualcuno può dirmi che cosa sta succedendo qui?

2) Una domanda un po 'estranei. Se dovessi fare qualcosa di orrendo come "delete altro" nel costruttore (portare con me), cosa succede quando qualcuno mi passa un puntatore a qualcosa sullo stack?

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

where 

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

Come posso fare in modo che il puntatore è legittimamente punta a qualcosa sul mucchio?

È stato utile?

Soluzione

Base<T> è un tipo di base di Derived<T>, ma Base<T>* non è un tipo di base di Derived<T>*. È possibile passare un puntatore derivato al posto di un puntatore base, ma non si può passare un riferimento puntatore derivato al posto di un riferimento di puntatore base.

Il motivo è che, suppongo che si possa, e supponiamo il costruttore di base erano di scrivere qualche valore nel riferimento:

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

Hai appena scritto un puntatore a qualcosa che è non un Derived<T>, in un puntatore a Derived<T>. Il compilatore non può permettere che questo accada.

Altri suggerimenti

  1. Non è possibile convertire un riferimento a un puntatore a Derivato a un riferimento a un puntatore alla base. (Modelli non contribuiscono al problema qui, quindi rimosso dal mio esempio qui sotto).
  2. Se si vuole rinviare la responsabilità di un puntatore, utilizzare un tipo di puntatore intelligente. tipi di puntatore intelligenti possono rappresentare la "responsabilità per eliminare" che i puntatori prime non può. Gli esempi includono std :: auto_ptr e boost :: shared_ptr , tra molti altri.

Perché non è possibile upcast riferimenti puntatore:

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

Quando si passa la vostra 'altra' parametro al ctor Base, si sta cercando di fare la stessa cosa come b_ptr = d_ptr sopra.

Si assicurarsi che puntatore punta a qualcosa sul mucchio, scrivendo che nella documentazione e basandosi sul chiamante riferirsi a tale. Se chi chiama il vostro costruttore passa un puntatore di stack, tutte le scommesse sono spenti, e non è colpa tua - si può provare a prendere il problema presto, ma non ci sono garanzie

.

Ecco come funziona la libreria standard -. Spesso ti cattura errori evidenti, ma non è tenuto a, ed è fino al chiamante per assicurarsi che essi non stanno facendo niente di stupido

La variabile x non è un puntatore, che dovrebbe essere se si desidera assegnare un new Derived<int> ad esso.

Per quanto riguarda l'eliminazione di cose in pila, non lo fanno. Non c'è modo per dire se v'è stato superato l'indirizzo di qualcosa sullo stack o sul mucchio (anzi, di serie il C ++ non ha nemmeno riconoscere l'esistenza di una pila). La lezione è che non si dovrebbe essere eliminando cose che non si è proprietari, soprattutto se non si ha modo di raccontare da dove sono venuti.

Non capisco perché vuoi riferimento al puntatore. Perché non

Base(Base<T> * other) { }

e

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

Che dovrebbe funzionare.

E, come altri hanno risposto, non credo che si può legittimamente sapere se il puntatore sta puntando in mucchio.

Modifica : perché non si può fare ciò che si sta cercando di: considerare esempio:

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

Dove Derived1 e Derived2 sono diverso classi derivate dalla base? Pensereste che sia legittimo? Ora che x di tipo Derived1 punti * per Derived2?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top