Home > Net >  Virtual function with non-shared method
Virtual function with non-shared method

Time:04-19

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>
{
    ...
}
  • Related