# 如何安全地使用基类指针进行子类的深拷贝
当初刚从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
```