Reputation: 35
I write small example CRTP pattern to better learn it and use it pattern in more complex code.
I want to use CRTP, that base class have access to derived class. All Ok, but i can't create few objects for my base class. If i at first call constructor for both objects Base<Derived1> base1; Base<Derived2> base2;
, and at second call function from each object base1.PrintDerived_FromA(); base2.PrintDerived_FromA();
, i have result:
Base constr work
Base constr work
b_: 0
b_: 25
but, i should have that:
Base constr work
Base constr work
b_: 9
b_: 25
If i call function right after constructor, all Ok:
Base<Derived1> base1;
base1.PrintDerived_FromA();
Base<Derived2> base2;
base2.PrintDerived_FromA();
Result:
Base constr work
b_: 9
Base constr work
b_: 25
It turns out a new constructor call overrides the existing object, but why? It is possible to fix this? And i want to use only CRTP, no virtual functions.
#include <iostream>
template <class T>
class Base {
public:
Base();
void PrintDerived_FromA();
void InitializeDerived();
};
class Derived1 : public Base<Derived1> {
public:
Derived1(int b);
void PrintDerived();
void SetDerived(int b);
private:
int b_;
};
class Derived2 : public Base<Derived2> {
public:
Derived2(int b);
void PrintDerived();
void SetDerived(int b);
private:
int b_;
};
template <typename T>
Base<T>::Base() {
InitializeDerived();
std::cout << "Base constr work" << std::endl;
}
template <>
void Base<Derived1>::InitializeDerived() {
static_cast<Derived1*>(this)->SetDerived(9);
}
template <>
void Base<Derived2>::InitializeDerived() {
static_cast<Derived2*>(this)->SetDerived(25);
}
template <typename T>
void Base<T>::PrintDerived_FromA() {
static_cast<T*>(this)->PrintDerived();
}
Derived1::Derived1(int b) : b_(b), Base() {
std::cout << "Derived1 constr work" << std::endl;
}
void Derived1::PrintDerived() {
std::cout << "b_: " << b_ << std::endl;
}
void Derived1::SetDerived(int b) {
b_ = b;
}
Derived2::Derived2(int b) : b_(b), Base() {
std::cout << "Derived2 constr work" << std::endl;
}
void Derived2::PrintDerived() {
std::cout << "b_: " << b_ << std::endl;
}
void Derived2::SetDerived(int b) {
b_ = b;
}
int main() {
Base<Derived1> base1;
Base<Derived2> base2;
base1.PrintDerived_FromA();
base2.PrintDerived_FromA();
return 0;
}
Upvotes: 1
Views: 111
Reputation: 37578
static_cast<Derived1*>(this)
cast is invalid: this
points at object of Base<Derived1>
type not at Derived1
. So dereferencing produced pointer causes Undefined Behavior. In order for CRTP to work you need to create objects of derived classes.
Upvotes: 1