为什么 CRTP 在我的函数中不起作用?

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

我正在学习CRTP C++模式

我的代码

template<class Type>
class BaseOrder {
public:
    void sendOrder() {static_cast<Type*>(this)->send();}
    void send() { cout << "Send Base" << endl;}
};

class DerivedOrder1 : public BaseOrder<DerivedOrder1> {
public:
    void send() { cout << "Send DerivedOrder1" << endl;}
};

class DerivedOrder2 : public BaseOrder<DerivedOrder2> {
public:
    void send() { cout << "Send DerivedOrder2" << endl;}
};

template<class T>
void handleOrder(BaseOrder<T> order) {
    order.send();
}

int main() {
    BaseOrder<DerivedOrder1> obj1;
    handleOrder(obj1); // Send Base

    BaseOrder<DerivedOrder2> obj2;
    handleOrder(obj2); // Send Base
}

我看到输出:

Send Base
Send Base

但我期待

Send DerivedOrder1
Send DerivedOrder2

如何修复我的代码?我错过了什么吗?

c++ crtp
2个回答
3
投票

您的代码中有几个错误:

send
不是
virtual
,您可能想改为拨打
sendOrder
。 并且您应该通过引用传递该参数,以避免切片,这会调用
sendOrder
UB,因为转换将无效:

template <class T>
void handleOrder(BaseOrder<T>& order) {
    order.sendOrder();
}

在main中,你没有创建派生类,它应该是

DerivedOrder1 obj1;
handleOrder(obj1); // Send Base

DerivedOrder2 obj2;
handleOrder(obj2); // Send Base

演示

避免这些错误的改进是制定一些方法

protected
:

template<class Type>
class BaseOrder {
protected:
    BaseOrder() = default;
    BaseOrder(const BaseOrder&) = default;
    BaseOrder& operator=(const BaseOrder&) = default;
public:
// ..
};

演示


-1
投票

    template<class T> void handleOrder(BaseOrder<T> order) { order.send(); }
该函数将 BaseOrder 类型的对象作为值。然而,这里有一个问题。如果将 BaseOrder 或 BaseOrder 类型的对象传递给此函数,则该对象将被“切片”并且仅采用 BaseOrder 部分。因此,当调用send函数时,只有BaseOrder类的send函数运行。

对于解决方案,您应该将handleOrder函数更改为:

template<class T> void handleOrder(BaseOrder<T>& order) { order.send(); }

这里重要的变化是它采用 BaseOrder& 参数。所以我们以物体作为参考。这样我们就可以保留原始派生类的类型而无需切片。进行此更改后,您可以得到您期望的输出:

© www.soinside.com 2019 - 2024. All rights reserved.