I'm on a personal project and I need to do something unusual. My code is kinda long but the problem comes from the structure so I'll use a very simplified version of the problem.
- I have two classes (A and B), with B derived from A.
- B uses every attributes and methods of A, including one which creates a modified clone of the instance of the class.
The problem is that I need to be able to use a method of B after cloning (moo in this case) that doesn't exists in A. I tried to make my methods virtual but it doesn't fix the problem. Is there any way to do this without CRTP ?
I really don't want to use CRTP because it would be really complicated. (In my real code I have a chain of 4 class inheritances, and all 4 are already templated)
#include <iostream>
class A
{
public:
/*Common function*/
virtual void foo(){
std::cout << "call from A" << std::endl;
}
A* clone(){
/*
...
... Code I don't want to write again for B
...
*/
return this;
}
};
class B: public A
{
public:
/*Common function*/
virtual void foo(){
std::cout << "call from B" << std::endl;
}
/*Not derived from A*/
void moo(){ //Doesn't work even with virtual keyword
std::cout << "only exist in B" << std::endl;
}
};
int main(int argc, char const *argv[])
{
auto tB = new B();
tB->foo();
tB->moo();
tB->clone()->foo();
tB->clone()->moo();
return 0;
}
Compilator:
error: 'class A' has no member named 'moo'; did you mean 'foo'?
38 | tB->clone()->moo();
| ^~~
| foo
I'm not English so sorry if it's unclear.
CodePudding user response:
Well, according to the comments, my research and how I think c works, I give up finding something that looks like virtual methods and still be satisfying.
So I resolved to use the CRTP, for those who are interested here's the code of my model of a 3 (I deleted one) inherited class CRTP with an additional type template argument :)
#include <iostream>
//CRTPI = "CRTP Interface", used for inheritances between CRTPs
template<typename Derived, typename T>
class CRTPI_A
{
protected:
T x = 0;
public:
T getX(){
return x;
}
Derived* clone(){
/*
...
... Code I don't want to write again for B and it's childs
...
*/
return new Derived();
}
};
template<typename Derived, typename T>
class CRTPI_B: public CRTPI_A<Derived, T>
{
public:
//Only for B and its childs
void iwd(){
std::cout << "Hi, i'm a B child !" << std::endl;
}
};
template<typename Derived, typename T>
class CRTPI_C: public CRTPI_B<Derived, T>{};
template<typename T>
class A: public CRTPI_A<A<T>, T>
{
public:
A(){};
A(T z){
this->x = z;
}
void foo(){
std::cout << "call from A" << std::endl;
}
};
template<typename T>
class B: public CRTPI_B<B<T>, T>
{
public:
B(){};
B(T z){
this->x = z;
}
void foo(){
std::cout << "call from B" << std::endl;
}
//Not in CRTP interface so won't be inherited by C
void UwU(){
std::cout << "I'm exclusive to B" << std::endl;
}
};
template<typename T>
class C: public CRTPI_C<C<T>, T>
{
public:
C(){};
C(T z){
this->x = z;
};
void foo(){
std::cout << "call from C" << std::endl;
}
};
int main(int argc, char const *argv[])
{
auto tA = new A<char>('A');
auto tB = new B<int>(2);
auto tC = new C<float>(420.69);
tA->foo();
tA->clone()->foo();
printf("\n");
tB->foo();
tB->iwd();
tB->clone()->foo();
tB->clone()->iwd();
tB->UwU();
printf("\n");
tC->foo();
tC->iwd();
// tC->UwU(); //Won't work but that's planned
std::cout << "\n" << tA->getX() << ":" << tB->getX() <<":" << tC->getX() << std::endl;
return 0;
}
Note that, here, the CRTP interface for C is optional because it has no child class and no exclusive methods, so we can just write:
template<typename T>
class C: CRTPI_B<C<T>, T>
{
...
}