Runtime polymorphism

I'm trying to achieve run time polymorphism however i am not quite sure how it's done.
Is the code example down a good way to do it or not? Will using it become bad in certain situations or slow down the program?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  class MyClass {
public:
	void calculate(int a, int b) {
		cout << a + b;
	}
};

inline MyClass* Class() {
	static MyClass instance;
	return &instance;
}

int main() {
	Class()->calculate;
}
Last edited on
fight agaisnt signature scanning
What do you mean by that ?
I was unsure how to start the question so i wrote that but afterwards forgot to change it.
Sorry my English is not very good. I fixed my question now.
Hello dimitar425 !

First, the structure of the class you posted is a singleton and i would strongly suggest avoiding it (google "why are singleton classes avoided in c++").

Second, don't use the inline keyword, it doesn't make the function inline it only recommends the compiler that it should be marked inline and the compiler decides if its appropriate, in short leave the compiler the work of figuring out what functions to inline as it will do so on its own for performance.

Third, consider dividing definition and implementation into .cpp and .h files

Now to your question:
Will using it become bad in certain situations or slow down the program?

your particular code wont slow down the program however if you intend on using runtime polymorphism know that you pay a penalty in performance in terms of vtables:
you call a function of a polymorphic base class -> than the vtable is searched for the correct function pointer to call -> only than is the correct function called.

Will using it become bad ? Only if you miss use it, or abuse it where it can be avoided.

Is the code example down a good way to do it or not?

Your example doesn't show polymorphism so il give a short example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>

class Base 
{
public:
  virtual void call()
  {
     std::cout << "do base\n";
  }
};

class Derived : public Base 
{
public:
  virtual void call() override
  {
      std::cout << "do derived\n";
  }
};

int main()
{
  //non dynamic way
  Derived d_a;
  Base& b_a = d_a;

  b_a.call();

  //dynamic way
  Base* b = new Derived();
  b->call();
  delete b;
}


A few warnings:
1)beware of slicing (read about it)
2)i used new and delete for a simple example however you should use unique_ptr for dynamic memmory
3)these is not the only way to use polymorphism (look up pure virtual functions and classes, and abstract classes)

lastly here is a source for design patterns : https://sourcemaking.com/design_patterns
it will provide you with examples that will help you design next projects.

EDIT:
After taking a second look at your class i have one question does CEngine inherit from MyClass ? if so still note that because there is no virtual methods in MyClass you will only be able to call calculate function unless you dynamic_cast the pointer to CEngine and call methods that way. if CEngine does not inherit from MyClass it will not compile. Besides from that its still not polymorphism.
Last edited on
Hello globaltourist

CEngine is a leftover from the original source. It should be:
1
2
3
4
inline MyClass* Class() {
	static MyClass instance;
	return &instance;
}


However could you explain me in which situations i should use these to create an object of class.
examples:
1
2
3
MyClass *object = new Myclass();
MyClass *object
MyClass object;
Last edited on
globaltourist wrote:
1
2
3
4
  //non dynamic way
  Derived d_a;
  Base& b_a = d_a;
  b_a.call();

This is not "non-dynamic", this demonstrates literally what dynamic polymorphism does (the second part of the demo with pointers just adds an indirection)

Speaking of the second part, there's a bug: line 37 delete b; is undefined behavior because Base destructor is non-virtual.

dimitar425 wrote:
CEngine is a leftover from the original source. It should be:
1
2
3
4
inline MyClass* Class() {
	static MyClass instance;
	return &instance;
}


Why would it return a pointer? When would it ever be null? Standard singleton in C++ returns a reference:
1
2
3
4
MyClass& Class() {
	static MyClass instance;
	return instance;
}

but as globaltourist correctly pointed out, singletons are bad code. See also C++ Core Guideline I.3 https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Ri-singleton

Nevertheless, I am going to guess you wanted your singleton to return a reference to some interface that defines that calculate function, where the most-derived class implements it. Let's imagine "CEngine" means "CalculationEngine" and "MyClass" is something like "AddAndPrintCalculationEngine"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
struct CEngine {
    virtual void calculate(int, int) = 0;
    virtual ~CEngine() {}
};
class MyClass : public CEngine {
public:
	void calculate(int a, int b) override {
		std::cout << a + b;
	}
};
CEngine& Class() {
	static MyClass instance;
	return instance;
}

int main() {
	Class().calculate(1, 2);
}



dimitar425 wrote:
However could you explain me in which situations i should use these to create an object of class.
MyClass object; - always, unless you're forced to do something else, like std::vector<MyClass> v(10); or std::make_unique<MyClass>

new MyClass - never. See https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Res-new


Last edited on
CEngine is a leftover from the original source. It should be:
edit that in the original post, it might confuse others that try to help you.

However could you explain me in which situations i should use these to create an object of class.

Sure.

1) use MyClass *object = new Myclass(); when you need to create an object on the go during runtime (making your own linked list will help you understand it best, there are many tutorials online for that). However don't forget to use delete on the pointer once you don't need the data it stores or else there will be a memory leak.
2)use MyClass *object whenever you need a pointer to a MyClass however don't forget to set it :
1
2
3
4
5
6
7
8
MyClass c;
MyClass* object = &c;

//or
MyClass* object = nullptr; 
//some lines of code
MyClass c;
object = &c;

3) use MyClass object; whenever possible (always prefer the stack to heap memory)

Lastly consider using unique_ptr and shared_ptr for dynamic memory
@Cubbi
This is not "non-dynamic", this demonstrates literally what dynamic polymorphism does (the second part of the demo with pointers just adds an indirection)
why is it considered dynamic polymorphism if the object is on the stack ?

Speaking of the second part, there's a bug: line 37 delete b; is undefined behavior because Base destructor is non-virtual.
yes this was done to simplify the example however i don't really see a point in a virtual destructor in base class if the derived class doesn't have any concrete one
globaltourist wrote:
why is it considered dynamic polymorphism if the object is on the stack ?

memory location of an object doesn't matter. Static polymorphism is resolved at compile time (through template specialization and overloading), dynamic polymorphism is resolved at run time (through an indirection to the final overrider)

globaltourist wrote:
i don't really see a point in a virtual destructor in base class if the derived class doesn't have any concrete one

undefined behavior doesn't care what programmers think about it: the program is free to launch nuclear missiles or miscompile in other funny ways.
Topic archived. No new replies allowed.