我有一个A类(来自我无法控制的库),有一个私有拷贝构造函数和一个克隆方法,还有一个从B派生的B类.我也想为B实现克隆.
天真的做法
#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); }
但是,失败了,因为A的复制构造函数是私有的:
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 {
解决方法
我认为你的B根本就没有公众成员,这是一个错字,
并且你错过了一个公共:在B :: B(int,int)的定义之前.
并且你错过了一个公共:在B :: B(int,int)的定义之前.
你A代表的班级的作者显然希望它成为
可复制但不可复制构造.这表明他或她想要所有
生活在堆上的实例.但相反,有公众
构造函数A :: A(int).你确定你是对的吗?
假设班级能够揭示足够的信息,这似乎是合理的
关于给定实例构成另一个实例.例如,推杆
在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_; };
如果这是真的,那么公共构造函数只会渲染它
绕过私有的,未定义的复制构造函数是不方便的:
A a0(1); A a1{a0.data()}; // Inconvenient copy construction
所以我不太相信A忠实地代表了这个问题
类.然而,从表面上看,你需要回答的问题
是:你甚至可以不方便地复制构建A吗?
如果没有,那么你就被困住了.如果是这样,那么你可以使用不方便的副本
构造A以明确定义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; }