CRTP 具有可用的基类,没有虚拟

问题描述 投票:0回答:1

有一个基类

Base
,它有很多功能,并且可以/应该按原样使用。但我想用(几个)
Derived
类来扩展它,而不用一堆虚拟/覆盖来污染原始类(因为,不确定哪些方法实际上需要从基本版本中更改)。当然,天真地让派生对象调用继承的方法会使该方法仅调用基类的方法,而不是任何重写的方法。

我尝试将其设为 CRTP,但问题似乎出在基类上;如果 Base 是一个模板,那么当类型当时不完整时,怎么可能有它自己的实例化?大多数其他 SO 问题似乎实际上并没有使用基类,而是将其保留为接口定义。或者,答案是否在当前硬编码 Base 的成员的函数模板中,而不是类模板中?

// template <class T = struct Base>
struct Base {
    Base& genericWrapper(); // return T&
    std::string specificConfig();
    Base& methodChaining(); // return T&
};

Base& Base::genericWrapper(){
    std::cout << "Base::genericWrapper():\n" << 
       /* T:: */ specificConfig() << std::endl;
    return *this; // T??
}

std::string Base::specificConfig(){
    return "Base::specificConfig()";
}

Base& Base::methodChaining(){
    std::cout << ".Base::methodChaining()\n";
    return *this;
}

struct Derived : public Base {
    std::string specificConfig();
    Derived& methodChaining(); // return T&
};

std::string Derived::specificConfig(){
    return "Derived::specificConfig()";
}

Derived& Derived::methodChaining(){
    std::cout << ".Derived::methodChaining()\n";
    return *this;
}

int main()
{
    Base b{};
    Derived d{};
    std::cout << "Base:\n";
    b.genericWrapper().methodChaining().methodChaining();
    std::cout << "\nDerived:\n";
    d.genericWrapper().methodChaining().methodChaining();

    return 0;
}

哪个打印:

Derived:
Base::genericWrapper(): // OK
Base::specificConfig()  // No
.Base::methodChaining() // Also no
.Base::methodChaining()
c++ templates crtp
1个回答
0
投票

如果你想使用CRTP,那么你确实需要一个基类模板,正如你所说,你不能实例化它本身,但你可以创建一个派生的

struct
来实例化基类模板,这不会改变行为(如下,
TriviallyDerived
)。 使用 CRTP 时,需要进行一些静态转换,如下所示。

#include <string>
#include <iostream>

template <class Derived>
struct Base {
    Derived& genericWrapper();
    std::string specificConfig();
    Derived& methodChaining();
};

template <class Derived>
Derived& Base<Derived>::genericWrapper(){
    std::cout << "Base::genericWrapper():\n" << 
       static_cast<Derived*>(this)->specificConfig() << std::endl;
    return static_cast<Derived&>(*this);
}

template <class Derived>
std::string Base<Derived>::specificConfig(){
    return "Base::specificConfig()";
}

template <class Derived>
Derived& Base<Derived>::methodChaining(){
    std::cout << ".Base::methodChaining()\n";
    return static_cast<Derived&>(*this);
}

struct Derived : Base<Derived> {
    std::string specificConfig();
    Derived& methodChaining();
};

std::string Derived::specificConfig(){
    return "Derived::specificConfig()";
}

Derived& Derived::methodChaining(){
    std::cout << ".Derived::methodChaining()\n";
    return *this;
}

struct TriviallyDerived : Base<TriviallyDerived> { };

int main()
{
    TriviallyDerived b{};
    Derived d{};
    std::cout << "Base:\n";
    b.genericWrapper().methodChaining().methodChaining();
    std::cout << "\nDerived:\n";
    d.genericWrapper().methodChaining().methodChaining();
}
© www.soinside.com 2019 - 2024. All rights reserved.