【发布时间】:2017-12-28 18:52:24
【问题描述】:
免责声明:仅当您想了解它是如何完成时才继续阅读。显然这是错误的,当你看到它时你会患上眼癌(我免疫,因为我是菜鸟:)
所以我考虑了一段时间 C++ 中的运行时多态性,我想出了以下内容。考虑一下这个
#include <iostream>
struct Animal
{
virtual ~Animal(){}
void make_noise() const {return do_make_noise();}
protected:
Animal( ){}
virtual void do_make_noise()const{std::cout << "Meh\n";}
};
struct Cat:public Animal
{
void do_make_noise()const{ std::cout<< "meow\n";}
};
struct Dog:public Animal
{
void do_make_noise()const{ std::cout<< "woof\n";}
};
int main()
{
Cat cat;
Dog dog;
Animal a((const Animal&)cat); //every tutorial teaches us that this is bad!!
a.make_noise();
a = (const Animal&)dog;
a.make_noise();
return 0;
}
如你所料,输出是
Meh
Meh
好的,对象切片很糟糕:/
但是现在让我稍微改变一下 Base 类:
struct Animal
{
virtual ~Animal(){}
void make_noise() const {return ptr_->do_make_noise();}
protected:
Animal( ):ptr_(this){}
Animal* ptr_;
virtual void do_make_noise()const{std::cout << "Meh\n";}
};
那么结果就是
meow
woof
哈哈。螺丝对象切片...
你怎么看呢?在我看来,能够按值复制并仍然获得多态行为有很多优点。人们不使用它有什么原因吗?还是我只是在这里重新发明轮子?
【问题讨论】:
-
这听起来像是无效指针取消引用灾难的秘诀。
-
现在你有一个对象 A 包含一个指向对象 B 的(非拥有的)指针。如果对象 B 先被销毁,你就有问题了。
-
如果你的子类有任何成员变量,切片仍然会搞砸。
-
不要认为你获得的收益相对于你必须投入的工作以使其稳定。您需要修复三规则违规,并且您将始终遇到上面讨论的不匹配的生命周期问题。再加上 Animal` 的所有后代都随身携带
ptr_并且永远不会使用它。我可以推荐使用std::unique_ptr吗? -
生命周期依赖在
Animal * a = &cat;中很明显,但对于您的Animal a = cat;则不是。
标签: c++ inheritance object-slicing