3

I am still learning and I have a question I am hoping someone can help me with:

Is it possible to achieve compile time polymorphism of different classes inheriting from the same base class to be used in an array without using virtual functions?

As anyone that knows even a little OOP with C++ if you have something like

class Base {
public:
   virtual void foo (){
    std::cout << "I'm the base" << std::endl;
   }
}

class A : public Base {
public:
  void foo() {
   std::cout << "I'm the child" << std::endl;
  }
} 

class B : public Base {
public:
  void foo() {
   std::cout << "I'm the child #2" << std::endl;
  }
} 


//Assume some main here

A *a = new A();
B *b = new B();

Base *someArray[] = {a,b};

someArray[0]->foo(); //"I'm the child"
someArray[1]->foo(); //"I'm the child #2"

We know this works because the functions are and inheritance is resolved run-time. However what I what to know is how to do this without virtual functions or if its possible to do this same thing without using virtual functions?

Suppose you do something like this

class Base {
public:
   void foo (){
    std::cout << "I'm the base" << std::endl;
   }
}

class A : public Base {
public:
  void foo() {
   std::cout << "I'm the child" << std::endl;
  }
} 

class B : public Base {
public:
  void foo() {
   std::cout << "I'm the child #2" << std::endl;
  }
} 


//Assume some main here

A *a = new A();
B *b = new B();

Base *someArray[] = {a,b};

someArray[0]->foo(); //"I'm the base"
someArray[1]->foo(); //"I'm the base"

So there is a lot of options but I can't seem to find something that will have the same behavior that I want. One solution I read about is making a static class template that works something like this

template <class T>
class Base
{
public:
    void interface()
    {
        // ...
        static_cast<T*>(this)->implementation();
        // ...
    }

    static void static_func()
    {
        // ...
        T::static_sub_func();
        // ...
    }
};

class Derived : Base<Derived>
{
public:
    void implementation() {
        std::cout << "I am derived" << std::endl;
    }
    static void static_sub_func();
};

class AlsoDerived : Base<Derived>
{
public:
    void implementation() {
        std::cout << "I am also derived" << std::endl;

    }
    static void static_sub_func();
};


//Assume in some main 

Derived div;
AlsoDerived alsoDiv;

Derived *someArray[] = { &div, &alsoDiv };//does not work not the same type 
Base *someArray[] = { &div, &alsoDiv }; //does not work b/c its a template 

The above is not the behavior I want. And then there is static casting which seem promising however I need to know what class its going to be at any given time which is not the behavior I want.

class Base {
public:
   void foo (){
    std::cout << "I'm the base" << std::endl;
   }
}

class A : public Base {
public:
  void foo() {
   std::cout << "I'm the child" << std::endl;
  }
} 

class B : public Base {
public:
  void foo() {
   std::cout << "I'm the child #2" << std::endl;
  }
} 


//Assume some main here

A *a = new A();
A *b = new A();
B *c = new B();

Base *someArray[] = {a,b,c};

someArray[0]->foo(); //"I'm the base"
static_cast<A*>(someArray[1])->foo(); //"I'm the child"
static_cast<B*>(someArray[2])->foo(); //"I'm the child #2"

This is very close to what I want however my problem is for the static_cast to work I need to know what class it is I want to static case and its not the behavior I want.

What do you think? Is there a better way do what I want?

Thanks for reading and if there is any confusion as to what I am asking please let me know so I can clarify.

4
  • Google "static polymorphism" Commented Apr 4, 2019 at 6:37
  • No it isn't. Think about your requirements: elements of an array has the same static type and polymorphism works with type information. Commented Apr 4, 2019 at 7:36
  • You have to manually track the derived class of each pointer. If you do, you don't gain much over using virtual methods. Why do you want this in the first place? Commented Apr 4, 2019 at 7:46
  • Welcome to SO, @boardkeystown! You may wish to consider using tuples instead of arrays. In any case, the type of your collection will have to encode the individual type of each element, and target function resolution will have to happen at compile-time, probably through an overloaded free function. Maybe replacing your hierarchy with a variant? Commented Apr 4, 2019 at 8:09

1 Answer 1

1

There is no real way to do what you want at compile time. Simply because you want your behavior to depend on the type of the object at run-time.

C++ offers run-time type dependent behavior through polymorphism, i.e. with virtual functions, and RTTI if needed. If you don't want to use this "natural way", you would have the following alternatives:

  • You know the type of the objects at compile-time (e.g. if you are sure that the first element is always an A* and the second is always a B*): In this case you can use static_cast like in the third case, or use templated code (e.g. if you prefer compile-time policies rather than run-time strategies). But it is generally not the way to handle random objects in a container.
  • You are able to find out yourself the type of the object and deduce the corresponding function to call: A typical way to do this is to have a typing field in the base class and use it to downcast with a static_cast. But this is not the best practice. And adding your own RTTI-like functionality rather than using the compiler's optimized one would not be more efficient than polymorphism.
  • You can use a std::variant or a std::any: These provide possibilities to offer some kind of run-time dependent behavior using compile-time features (an without necessarily requiring the alternative types to be derived from a common base).

The remaining question would be why you want to avoid the normal polymorphism if you need it.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.