2016-04-07 19 views
5

Ho 2 classi, A e B. In A ho 3 campi privati. Nella classe B vorrei scrivere un costruttore di copia e inizializzare i campi privati ​​dalla classe A. Tuttavia, questo non funziona:Ereditarietà e copia costruttore: come inizializzare i campi privati ​​dalla classe base?

#include <iostream> 
#include <string> 
using namespace std; 

class A 
{ 
    private: 

     string *field1; 
     string *field2; 
     string *field3; 
     double num1; 

    public: 

     A(string *o, string *n, string *m, double a=0) 
     { 
      field1 = new string(*o); 
      field2 = new string(*n); 
      field3 = new string(*m); 
      num1 = a; 
     } 

     A(const A& other) { 
      field1 = new string(*other.field1); 
      field2 = new string(*other.field2); 
      field3 = new string(*other.field3); 
      num1 = other.num1; 
     } 

     void show() 
     { 
      cout << *field1 << " " << *field2 << " " << *field3 << "\n"; 
     } 

     ~A() 
     { 
      delete field1; 
      delete field2; 
      delete field3; 
     } 
}; 

/*--------------------------------------------------------------------------------------------*/ 

class B : public A 
{ 
    private : 

     double num2; 
     double num3; 

    public: 

     B(double num2, double num3, string *o, string *n, string *num, double a=0) : A(o,n,num,a) 
     { 
      this->num2 = num2; 
      this->num3 = num3; 
     } 

     B(const B& other) : A(other.field1, other.field2, other.field3, other.num1) 
     { 
      num2 = other.num2; 
      num3 = other.num3; 
     } 

     void show() 
     { 
      cout << num2 << " " << num3 << "\n"; 
      A::show(); 
     } 
}; 

int main() 
{ 
    string o = "TEXT 111"; 
    string *optr = &o; 

    string n = "TEXT 222"; 
    string *nptr = &n; 

    string *numptr = new string("9845947598375923843"); 

    A ba1(optr, nptr, numptr, 1000); 
    ba1.show(); 

    A ba2(ba1); 
    ba2.show(); 

    A ba3 = ba2; 
    ba3.show(); 

    B vip1(20, 1000, optr, nptr, numptr, 3000); 
    vip1.show(); 

    B vip2(vip1); 
    vip2.show(); 

    delete numptr; 
    return 0; 
} 

Capisco che quando cambio private-protected dovrebbe funzionare (e lavora, naturalmente) - ma come affrontare la situazione che ho nel mio codice? La domanda è: come inizializzare, in copy constructor, i campi privati ​​dalla classe base? Ottengo i seguenti errori con il codice corrente:

/home/yak/test.cpp|9|error: ‘std::string* A::field1’ is private| 
/home/yak/test.cpp|61|error: within this context| 
/home/yak/test.cpp|10|error: ‘std::string* A::field2’ is private| 
/home/yak/test.cpp|61|error: within this context| 
/home/yak/test.cpp|11|error: ‘std::string* A::field3’ is private| 
/home/yak/test.cpp|61|error: within this context| 
/home/yak/test.cpp|12|error: ‘double A::num1’ is private| 
/home/yak/test.cpp|61|error: within this context| 
||=== Build failed: 8 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===| 
+1

Li rendete "protetti" come avete suggerito, quindi li accedete dal corpo di B. Qual è il problema nel renderli "protetti"? – RJFalconer

+0

Se non puoi cambiare 'A', allora quello che stai chiedendo è impossibile. E il tuo codice perde e non fa eccezione alle eccezioni. Perché usare i puntatori alle stringhe ?! –

+0

@RJFalconer: Sono curioso, cosa devo fare per inizializzare i campi 'private' dalla classe figlio. Come si vede, con l'elenco di inizializzazione non funziona – yak

risposta

6

Tutto quello che dovete fare è chiamare il costruttore copia della A quando si copia costruire B come

B(const B& other) : A(other) 
{ 
    num2 = other.num2; 
    num3 = other.num3; 
} 

Dal B eredita da A questo è legale e A copierà la parte A di other.

Si noti inoltre che tutti questi puntatori non sono necessari e rendono il codice più complicato. Potremmo riscriverlo come:

class A 
{ 
private: 
    string field1; 
    string field2; 
    string field3; 
    double num1; 

public: 
    A(const string& o, const string& n, const string& m, double a = 0) : field1(o), field2(n), feild3(m), num1(a) {} 

    A(const A& other) field1(other.field1), field2(other.field2), feild3(other.feild3), num1(other.num1) {} 

    void show() 
    { 
     cout << field1 << " " << field2 << " " << field3 << "\n"; 
    } 
}; 

/*--------------------------------------------------------------------------------------------*/ 

class B : public A 
{ 
private: 

    double num2; 
    double num3; 

public: 

    B(double num2, double num3, const string& o, const string& n, const string& m, double a = 0) : A(o, n, num, a), num2(num2), num3(num3) {} 

    B(const B& other) : A(other), num2(other.num2), num3(other.num3) {} 

    void show() 
    { 
     cout << num2 << " " << num3 << "\n"; 
     A::show(); 
    } 
}; 
+0

Come 'A' sa quale 'parte' di' other' dovrebbe copiare? È perché ho un costruttore di copia in 'A'? – yak

+0

@yak That e [object slicing] (http://stackoverflow.com/questions/274626/what-is-object-slicing) (non è un problema qui). – LogicStuff

+0

@LogicStuff: Grazie – yak

0

È necessario richiamare costruttore di copia genitore dal costruttore di copia, dandogli lo stesso argomento.

1

Quando si utilizza il costruttore di copia per la classe B, è necessario chiamare il costruttore di copia per la classe A.

Quindi, sostituire il codice per questo:

B(const B& other) : A(other) 
    { 
     num2 = other.num2; 
     num3 = other.num3; 
    } 

Inoltre, dichiarare il distruttore dalla classe A come virtuale. E suppongo che tu voglia farlo anche per il metodo show().