2015-06-05 16 views
7

Ich habe eine Klasse A (aus einer Bibliothek, über die ich keine Kontrolle habe) mit einem privaten Kopierkonstruktor und einer clone Methode und einer Klasse B abgeleitet von A. Ich möchte auch clone für B implementieren.Kopierkonstruktor wird implizit gelöscht, da die Standarddefinition schlecht formatiert wäre

Der naive Ansatz

#include <memory> 

class A { // I have no control here 
    public: 
    A(int a) {}; 

    std::shared_ptr<A> 
     clone() const 
     { 
     return std::shared_ptr<A>(new A(*this)); 
     } 

    private: 
    A(const A & a) {}; 
}; 

class B: public A { 
    public: 
    B(int data, int extraData): 
     A(data), 
     extraData_(extraData) 
    { 
    } 

    std::shared_ptr<B> 
    clone() const 
    { 
     return std::shared_ptr<B>(new B(*this)); 
    } 

    private: 
    int extraData_; 
}; 

int main() { 
    A a(1); 
} 

jedoch fehl, da der Kopierkonstruktor von A ist privat:

main.cpp: In member function ‘std::shared_ptr<B> B::clone() const’: 
main.cpp:27:42: error: use of deleted function ‘B::B(const B&)’ 
    return std::shared_ptr<B>(new B(*this)); 
            ^
main.cpp:17:7: note: ‘B::B(const B&)’ is implicitly deleted because the default definition would be ill-formed: 
class B: public A { 
    ^
main.cpp:14:5: error: ‘A::A(const A&)’ is private 
    A(const A & a) {}; 
    ^
main.cpp:17:7: error: within this context 
class B: public A { 

könnte es eine Möglichkeit, den Einsatz von A::clone() für B::clone() zu machen, aber ich bin nicht sicher, wie das genau funktionieren würde. Irgendwelche Hinweise?

Antwort

2

Sie benötigen die Kopie-Konstruktor A geschützt zu machen, so dass die abgeleitete Klasse könnte es benutzen:

protected: 
    A(const A & a) { /*...*/ } 

Hoffnung, das hilft.

+0

Ich habe keine Kontrolle über 'A', da es aus einer Bibliothek kommt; Ich habe dies im ursprünglichen Beitrag geklärt. –

+1

Dann sollten Sie nicht von 'A' abgeleitet werden. – Peter

+0

@ NicoSchlömer: Ohh .. in diesem Fall ist es eine schlechte Idee, von 'A' abzuleiten. Sie sollten nun Komposition anstelle von Vererbung verwenden. – Nawaz

1

Der Grund für die Standarddefinition von B ‚s Konstruktor kopieren ist schlecht ausgebildet ist, weil - wenn es erlaubt war - der private berufen würde (also unzugänglich B) und nicht definiert Copykonstruktor von A.

Machen Sie A Copy Constructor entweder geschützt oder öffentlich, so dass es zugänglich ist B. Eine andere (wirklich schlechte) Option ist die Klasse B als Freund von A zu deklarieren. Für alle Möglichkeiten müssen Sie außerdem eine Definition für den Kopierkonstruktor A angeben.

+0

Ich habe keine Kontrolle über A, da es aus einer Bibliothek stammt; Ich habe dies im ursprünglichen Beitrag geklärt. –

+0

Gemäß den Kommentaren, die ich als Antwort auf diese Klarstellung (unter Nawazs Post) gemacht habe, einen privaten Konstruktor zu haben, ist ein ziemlich bedeutender Hinweis, dass Sie nicht von A abgeleitet sein sollten. – Peter

+0

Gibt es keine Möglichkeit, 'A :: clone()' entweder zu verwenden? –

3

Ich nehme an, es ist ein Tippfehler, dass Ihre B keine öffentlichen Mitglieder überhaupt hat, und dass Sie ein public: vor der Definition von B::B(int,int) fehlen.

Der Autor der Klasse, die von Ihrer A vertreten wird, will es offenbar klonbaren, aber nicht konstruierbar kopieren. Das würde bedeuten, dass er alle Instanzen auf dem Heap leben möchte. Aber im Gegensatz dazu gibt es die Öffentlichkeit Erbauer A::A(int). Bist du sicher, dass du recht hast?

Es ist plausibel anzunehmen, dass die Klasse genügend Informationen über eine bestimmte Instanz offen legen kann, um eine andere Instanz zu bilden. ZB setzt ein wenig mehr Fleisch auf A:

class A { 
public: 
    A(int a) 
    : data_(a){}; 

    std::shared_ptr<A> 
    clone() const 
    { 
     return std::shared_ptr<A>(new A(*this)); 
    } 

    int data() const { 
     return data_; 
    } 

private: 
    A(const A & a) {}; 
    int data_; 
}; 

Und wenn die wahr ist, dann würde der öffentliche Konstruktor es macht nur unbequem, den privaten, nicht definiert Copykonstruktor zu umgehen:

A a0(1); 
A a1{a0.data()};  // Inconvenient copy construction 

So bin ich weniger als zuversichtlich, dass A treu das Problem Klasse darstellt. Nehmen Sie es jedoch zum Nennwert, die Frage, die Sie beantworten müssen: lautet: Kannst du sogar unpassend kopieren einA konstruieren?

Wenn nicht, dann bist du fest. Wenn dies der Fall ist, können Sie die Konstruktion A verwenden, um ausdrücklich einen konventionellen Kopierkonstruktor für B, zu definieren, der alles ist, was Sie brauchen. Z.B.

class B: public A { 
public: 
    B(B const & other) 
    : A(other.data()),extraData_(other.extraData_){}  

    B(int data, int extraData): 
    A(data), 
    extraData_(extraData) 
    { 
    } 

    std::shared_ptr<B> 
    clone() const 
    { 
     return std::shared_ptr<B>(new B(*this)); 
    } 

    int extradata() const { 
     return extraData_; 
    } 

private: 
    int extraData_; 
}; 

#include <iostream> 

int main() 
{ 
    B b(1,2); 
    std::shared_ptr<B> pb = b.clone(); 
    std::cout << pb->data() << std::endl; 
    std::cout << pb->extradata() << std::endl; 
    return 0; 
}