# 如何安全地使用基类指针进行子类的深拷贝 当初刚从C++转到Java时,觉得接口概念很神奇并且貌似没有什么用处。然而用惯了它以后,再回到C++,却时常因为C++的虚函数/继承机制没有Java接口用着方便而烦心。 今天编一个仿真程序就碰上了问题:某个`任务X`有好几种算法`算法A`、`算法B`并且都有可能用到,于是写了个带虚函数的基类,然后用两种方法去继承,代码大概如下: #include class A { public: virtual void fuck()=0; }; class B : public A { public: B(int t) : t(t) {} B(const B &src) { t = src.t; } int t; void fuck() override { std::cout << "Fuck B " << t << " times." << std::endl; } }; class C : public A { public: C(int t) : t(t) {} C(const C &src) { t = src.t; } int t; void fuck() override { std::cout << "Fuck C " << t << " times." << std::endl; } }; int main() { A *ab = new B(233); ab->fuck(); A *ac = new C(666); ac->fuck(); return 0; } 输出: ``` Fuck B 233 times. Fuck C 666 times. ``` 同样的`A*`指针给出了不同的结果,操作是成功的。然而下一步需求就复杂了:由于某些原因,需要从一个`A*`做深拷贝。 显然,不能直接实例化一个`A`然后逐个拷贝元素,因为A不能直接被实例化。然而,需要做拷贝的地方是不知道这个指针究竟指向的是`B`还是`C`的(如果这也要手动处理,我还不如去写一堆`if`呢)。 那么按虚函数机制,写一个虚的`virtual A(const A &a)=0;`呢?也不行,构造函数就是为了实例化对象,不能为虚。至此为止,貌似山穷水尽。 思考一下,还是要从虚函数机制下手,必须通过虚函数机制,才能从一个`A*`调用到`B`或者`C`里面去。**构造函数不让玩虚的,就自己来一个普通的函数代替嘛。** 按这个思路,一个`virtual A *copy()=0;`就可以解决问题了,经验证,除了编码稍微麻烦了些之外,没什么隐患,代码与输出如下: #include class A { public: virtual A *copy()=0; virtual void fuck()=0; virtual ~A() { std::cout << "Stop fucking around" << std::endl; } }; class B : public A { public: B(int t) : t(t) {} B(const B &src) { t = src.t; } int t; A *copy() override { std::cout << "I am B and I am making a copy of A" << std::endl; return new B(*this); } void fuck() override { std::cout << "Fuck B " << t << " times." << std::endl; } ~B() override { std::cout << "Stop fucking B around" << std::endl; } }; class C : public A { public: C(int t) : t(t) {} C(const C &src) { t = src.t; } int t; A *copy() override { std::cout << "I am C and I am making a copy of A" << std::endl; return new C(*this); } void fuck() override { std::cout << "Fuck C " << t << " times." << std::endl; } ~C() override { std::cout << "Stop fucking C around" << std::endl; } }; int main() { A *ab = new B(233); ab->fuck(); A *ab_copy = ab->copy(); ab_copy->fuck(); A *ac = new C(666); ac->fuck(); A *ac_copy = ac->copy(); ac_copy->fuck(); std::cout << "Address: ab: " << ab << "\tab_copy: " << ab_copy << "\tac: " << ac << "\tac_copy:" << ac_copy << std::endl; delete ab; delete ab_copy; delete ac; delete ac_copy; return 0; } 输出: ``` Fuck B 233 times. I am B and I am making a copy of A Fuck B 233 times. Fuck C 666 times. I am C and I am making a copy of A Fuck C 666 times. Address: ab: 0x13f0c20 ab_copy: 0x13f1050 ac: 0x13f1070 ac_copy:0x13f1090 Stop fucking B around Stop fucking around Stop fucking B around Stop fucking around Stop fucking C around Stop fucking around Stop fucking C around Stop fucking around ```