如何包装一个类然后调用它的方法?

时间:2017-12-30 10:08:17

标签: c++

目标是拥有一个可以改变其行为的物体 我的对象是包装器,它应该调用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;
}

4 个答案:

答案 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;
}