0

使用 CRTP 时,我遇到了对象切片问题。以下模拟说明了我的问题。

#include <memory>

class CrtpGenr
{
};

template<class t_object>
class CrtpBase : public CrtpGenr
{
    public:
        static
        auto create() -> std::unique_ptr<t_object> {
            return(std::unique_ptr<t_object>(new t_object));
        }
        void funct1(){}
};

class CrtpDirv1 : public CrtpBase<CrtpDirv1>
{
    public:
        void funct2(){}
};

class CrtpDirv2 : public CrtpBase<CrtpDirv2>
{
    public:
        void funct2(){}
};


int main()
{
/*
    // This works
    std::unique_ptr<CrtpDirv1> crtp_obj = CrtpDirv1::create();
    crtp_obj->funct1();
    crtp_obj->funct2();
*/

    std::unique_ptr<CrtpGenr> crtp_obj1 = static_cast<std::unique_ptr<CrtpGenr>>(CrtpDirv1::create());
    std::unique_ptr<CrtpGenr> crtp_obj2 = static_cast<std::unique_ptr<CrtpGenr>>(CrtpDirv2::create());
    crtp_obj1->funct1();
    crtp_obj1->funct2();

    return 0;
}

编译上面的代码给我以下错误:

main.cpp: In function 'int main()':
main.cpp:47:16: error: 'class CrtpGenr' has no member named 'funct1'
 crtp_obj1->funct1();
            ^
main.cpp:48:16: error: 'class CrtpGenr' has no member named 'funct2'
 crtp_obj1->funct2();

我希望能够将 CrtpDirv1 和 CrtpDirv2 类转换为 CrtpGenr。这样我就可以定义一个 CrtpGenr 类型的容器来保存 CrtpDirv1 或 CrtpDirv2 的对象。我究竟做错了什么?

4

1 回答 1

0

*crtp_obj1是类型CrtpGenr-正如您在第 48 行中所声称的那样。这实际上是正确的,因为整个 shebang 源自CrtpGenr. 所以 static_casts 编译。

但是你把继承的事情搞反了,我想。看看 的定义CrtpGenr

class CrtpGenr
{
};

它没有方法。为什么您希望编译器允许您尝试在该对象上调用一个?!

如果您进行强制转换,以便可以将某些常见基本类型的对象放入容器中(例如,`std::list'),那么您可以这样做,但是当您想调用该对象上的特定方法时,您需要通过将该指针转换回您创建的类型来告诉编译器它到底是什么类型的对象。

您可能想更深入地研究继承和多态性。例如,也许CrtpGenr类可以具有funct1()派生类实现的虚拟方法。

于 2016-03-30T06:37:17.863 回答