Why is CRTP not working in the following function?

107 Views Asked by At

I am learning CRTP C++ pattern

My code

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
}

I see output:

Send Base
Send Base

But I expect

Send DerivedOrder1
Send DerivedOrder2

How to fix my code? Did I miss something?

1

There are 1 best solutions below

0
Jarod42 On BEST ANSWER

There are several mistakes in your code:

send is not virtual, you probably want to call sendOrder instead. and you should pass that argument by reference to avoid slicing which would make the call to sendOrder UB as the cast would be invalid:

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

in main, you don't create the derived class, it should be

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

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

Demo

An improvement to avoid those mistakes would be to make some methods protected:

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

Demo