目标是拥有一个可以改变其行为的物体
我的对象是包装器,它应该调用One :: handler()并输出“One”,而是从Situation :: handler()输出“来自虚拟处理程序”。
我没有写改变方法因为我在这里。
#include <iostream>
class Situation
{
public:
virtual void handler()
{
std::cout<<"from virtual handler()";
}
};
class Wrap
{
private:
Situation _sit;
public:
Wrap(Situation sit)
{
_sit = sit;
}
void call()
{
_sit.handler();
}
};
class One : public Situation
{
public:
void handler()
{
std::cout<<"One"<<std::endl;
}
};
int main()
{
One first;
Wrap wrapper(first);
wrapper.call();
return 0;
}
答案 0 :(得分:3)
由于object slicing,您无法包装按值传递的多态对象。你的Wrapper
需要有一个指针或对它包装的对象的引用。
以下是使用引用的实现:
class Wrap
{
private:
Situation& _sit;
public:
Wrap(Situation& sit) : _sit(sit)
{
}
void call()
{
_sit.handler();
}
};
请注意,此实现与原始实现几乎相同,在两个位置添加了&
,初始化列表用于设置_sit
引用。但是,它很脆弱,因为您必须确保_sit
引用的对象的生命周期超出其使用Wrapper
的最后一个点。
更强大的包装器实现将使用智能指针来动态分配对象。
答案 1 :(得分:1)
由于您的包装器通过复制获取(并存储)其Situation对象,导出的类型信息将丢失,所有剩余的都将是基类,这称为切片。
如果要保持派生部件传递指针或对包装器构造函数的引用,并将成员类型更改为某种指针类型(如果包装器要获取派生类型实例的wicership,则可能是unique_ptr)。
答案 2 :(得分:0)
您通过first
参数按值传递sit
。这意味着sit
是您声明的first
类型Situation
的副本,而不是类型one
的原始One
。顺便说一句,你只复制了班级One
的一小部分。
要调用虚方法,您应该通过引用或指针传递对象one
。
答案 3 :(得分:0)
您的问题是通过值而不是引用或指针传递基类的对象 - 您基本上将One
强制转换为Situation
(同时剥离额外数据),从而获得结果
事实上,既然你正在使用多态(虚拟成员和继承),你甚至不需要你的包装器开头:
class Situation {
public:
virtual void handle() {
std::cout << "Base Situation" << std::endl;
}
}
class One : public Situation {
public:
virtual void handle() {
std::cout << "One Situation" << std::endl;
}
}
int main(int argc, char **argv) {
// These pointers point to any base class object or derived object
Situation *first = new Situation();
Situation *second = new One();
// Calling a virtual member will automatically call the most derived class's member
first->handle(); // prints "Base Situation"
second->handle(); // prints "One Situation"
delete first;
delete second;
}