why do i need polymorphism

Pages: 12
a00,
Template don't work anymore.


Are you sure? :-) I will put only one line of code, and this will work

1
2
3
4
template<class t>
void doAThingTwo(t one){
	one.memberFunction(1);
}


Look now:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <iostream>
using namespace std;

class A{
public:
	A();
	~A();
	virtual void memberFunction();
	virtual void memberFunction(int);
private:
};

class B : public A{
public:
	B();
	~B();
	virtual void memberFunction();
	// In A class you have overloading of memberFunction()
	// So you put this line of code.
        // In this way, all the overloading functions of the base class A,
        // that you are not override in class B will attempt to be called if
        // B::memberFucntion() argument(s) don't match.
	using A::memberFunction;
private:
};

class C : public B{ // C don't have C::memberFunction
public:
	C();
	~C();
private:
};

class D{
public:
	D();
	~D();
private:
};

template<class t>
void doAThing(t);

template<class t>
void doAThingTwo(t);

void doAThingThree(A&);

int main(){
	A one;
	B two;
	C three; // C object
	D four;
    doAThing(one);
	doAThing(two);
	doAThing(three); // It calls B::memberfunction
//	doAThing(four);
        //Now doAThingTwo will work.
	doAThingTwo(three);
	doAThingThree(three);
    
        std::cout << std::endl << "Do you see how it works?" << std::endl;
        three.memberFunction();
        three.memberFunction(2);

	system("pause");
	return 0;
}

template<class t>
void doAThing(t one){
	one.memberFunction();
}

template<class t>
void doAThingTwo(t one){
	one.memberFunction(1);
}

void doAThingThree(A& one){
	one.memberFunction(1);
}


A::A(){
	
}

A::~A(){
	
}

void A::memberFunction(){
	cout << "from A" << endl;
}

void A::memberFunction(int one){
	cout << "from A int" << endl;
}

B::B(){
	
}

B::~B(){
	
}

void B::memberFunction(){
	cout << "from B" << endl;
}

C::C(){
	
}

C::~C(){
	
}

D::D(){
	
}

D::~D(){
	
}
Last edited on
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
using namespace std;

class A{
public:
	A(){};
	~A(){};
	virtual void memberFunction(){cout << "From A" << endl;}
	virtual void memberFunction(int){cout << "From A int" << endl;}
private:
};

class B : public A{
public:
	B(){};
	~B(){};
	virtual void memberFunction(){
	    cout << "From B" << endl;
	    // Sometimes you want to call the base class virtual
	    // functions inside overriding derived virtual.
	    // For example, if you want all functionality of base class virtual,
	    // but in same time to add something new
	    cout << "But calling A::memberFuntion() and A::memberFuntion(1) too:" << endl;
	    A::memberFunction();
	    A::memberFunction(1);
            cout << endl;
	    }
	using A::memberFunction;
private:
};

class C : public B{ // C don't have C::memberFunction
public:
	C(){};
	~C(){};
	// You can call A::memberFunction(int) inside C class too.
	void callA(){
	    cout << "I calling A class memberFuntion(int) inside C class:" << endl;
	    A::memberFunction(2);
	    }
private:
};

int main()
{
    C obj;
    obj.memberFunction();
    
    obj.callA();
    
    // I even can do direct call of all memberFunctions of all classes under C;
    cout << endl << "Call directly all memberFunctions in class A and B from C:" << endl;
    obj.A::memberFunction();
    obj.A::memberFunction(3);
    obj.B::memberFunction();
}



From B
But calling A::memberFuntion() and A::memberFuntion(1) too:
From A
From A int

I calling A class memberFuntion(int) inside C class:
From A int

Call directly all memberFunctions in class A and B from C:
From A
From A int
From B
But calling A::memberFuntion() and A::memberFuntion(1) too:
From A
From A int
Last edited on
And something very important too.

Please use override and final specifiers.

override make compiler to check if your function really override something from base class and if not give error.

virtual void memberFunction() override

Or you can make simple mistake like this one and a long time to wonder what's going on:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
using namespace std;

class A{
public:
	A();
	~A();
	virtual void memberFunction();
	virtual void memberFunction(int);
private:
};

class B : public A{
public:
	B();
	~B();
	//Do you see little mistake I make
	virtual void memberFunctions();
	using A::memberFunction;
private:
};

template<class t>
void doAThing(t);

int main(){
	A one;
	B two;

       doAThing(one);
       doAThing(two);


       system("pause");
       return 0;
}

template<class t>
void doAThing(t one){
	one.memberFunction();
}


A::A(){
	
}

A::~A(){
	
}

void A::memberFunction(){
	cout << "from A" << endl;
}

void A::memberFunction(int one){
	cout << "from A int" << endl;
}

B::B(){
	
}

B::~B(){
	
}

//This can be automaticlly generete, 
//for example by Visual Studio
//and your 's' mistake
//will spread without notice
void B::memberFunctions(){
	cout << "from B" << endl;
}


Using override and it will not compile:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
using namespace std;

class A{
public:
	A();
	~A();
	virtual void memberFunction();
	virtual void memberFunction(int);
private:
};

class B : public A{
public:
	B();
	~B();
	//Do you see little mistake I make
	virtual void memberFunctions() override;
	using A::memberFunction;
private:
};

template<class t>
void doAThing(t);

int main(){
	A one;
	B two;

        doAThing(one);
	doAThing(two);


	system("pause");
	return 0;
}

template<class t>
void doAThing(t one){
	one.memberFunction();
}


A::A(){
	
}

A::~A(){
	
}

void A::memberFunction(){
	cout << "from A" << endl;
}

void A::memberFunction(int one){
	cout << "from A int" << endl;
}

B::B(){
	
}

B::~B(){
	
}

//This can be automaticlly generete, 
//for example by Visual Studio
//and your 's' mistake
//will spread without notice
void B::memberFunctions(){
	cout << "from B" << endl;
}


Also you can use final specifier to tell compiler that any attempt to override, for this example A::memberFucntion(int) in derived classes will be prevent and compiler will give error.

so this:
1
2
3
4
5
6
7
8
class A{
public:
	A();
	~A();
	virtual void memberFunction();
	virtual void memberFunction(int) final;
private:
};



will give error here:
1
2
3
4
5
6
7
8
9
10
11
class B : public A{
public:
	B();
	~B();
	//Do you see little mistake I make
	virtual void memberFunction() override;
        // You can't override A::memberFunction(int) final
	virtual void memberFunction(int) override{};
	using A::memberFunction;
private:
};


P.s. Most developers believe that the use of these specifiers override and final are unnecessary luxury. But when I see a code written without their use I already know : "This programmer is a gambling type. He/she is inclined to create very nasty bugs and can embitter the lives of everyone around him/her.". So if I'm the Boss, and you come to me for a job interview and I saw that you did not use override I will say you goodbye without even thinking about it.

Someone may consider this to be extreme. For example, I can give you a task to do two classes. One abstract class A with empty destructor, and one derived from it, class B also with empty destructor - one pure virtual function f in A, and override f in B:

This is what I don't want to see:

1
2
3
4
5
6
7
8
9
10
11
12
13
class A
{
public:
	virtual void f() = 0;
	~A(){};
};

class B : public A
{
public:
	virtual void f() {};
	~B(){};
};


This is what I will admire:

1
2
3
4
5
6
7
8
9
10
11
12
13
class A
{
public:
	virtual void f() = 0;
	virtual ~A(){};
};

class B : public A
{
public:
	virtual void f() override {};
	virtual ~B(){};
};


Everyone can make mistakes. But smart people are making efforts to reduce the chance of making such mistakes.
Last edited on
Example of memory leak, because of the lack of one-word "virtual" in abstract base destructor!

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>
#include <vector>
using namespace std;

// Base abstract class
class A
{
public:
	virtual void showChar() = 0;
    ~A() { cout << "Destructor ~A call" << endl; }
};

// Derived from A
class B : public A
{
public:
	char* pC = new char('B');

	// override showChar()
	virtual void showChar() override {
		cout << "B::showChar() called : " << *pC << endl; 
	}

	// Destructor
	~B() { 
		cout << "Destructor ~B call , delete pC" << endl;
		delete pC;
	}
};

// Derived from B
class C : public B
{
public:
	//container
	std::vector<A*> objs;

	// Push n number of B'class objects in vector objs
	void pushObjs(int n)
	{
		for(int i = 1; i<= n; i++)
			objs.push_back(new B);
	}

	// override showChar()
	virtual void showChar() override{
		cout << "C::showChar called : " << endl;
		for (A* a : objs)
			a->showChar();
		cout << "END C::showChar" << endl << endl;
	}
	
	//Destructor
	~C(){ 
		cout << "BEGIN Destructor ~C call, objs delete" << endl;
		for (A* a : objs)
		{
			delete a;
		}
                objs.clear();
		cout << "END Destructor ~C" << endl << endl;
	};
};

int main()
{
	C obj{};
	// Create and push 3 objects from class B in obj.objs vector.
	obj.pushObjs(3);
	// Show pC virables of these 3 B class objects
	obj.showChar();

	cout << endl << "Releasing obj after program end :" 
		<< endl << endl;
}



C::showChar called : 
B::showChar() called : B
B::showChar() called : B
B::showChar() called : B
END C::showChar


Releasing obj after program end :

BEGIN Destructor ~C call, objs delete
Destructor ~A call
Destructor ~A call
Destructor ~A call
END Destructor ~C

Destructor ~B call , delete pC
Destructor ~A call


How many times you see "Destructor ~B call , delete pC" when program release obj?

You must see it 4 times.

1. obj himself derived from B class, so it have one pC pointer and you can call it:

cout << *obj.pC << endl;

It is released properly when program end.

2. When ~C destructor delete obj.objs you must see 3 more times "Destructor ~B call , delete pC" but you don't. This mean only one thing:

MEMORY LEAK!

So you can make base class ~A destructor virtual and everything will be resolve.
virtual ~A() { cout << "Destructor ~A call" << endl; }

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>
#include <vector>
using namespace std;

// Base abstract class
class A
{
public:
	virtual void showChar() = 0;
    virtual ~A() { cout << "Destructor ~A call" << endl; }
};

// Derived from A
class B : public A
{
public:
	char* pC = new char('B');

	// override showChar()
	virtual void showChar() override {
		cout << "B::showChar() called : " << *pC << endl; 
	}

	// Destructor
	~B() { 
		cout << "Destructor ~B call , delete pC" << endl;
		delete pC;
	}
};

// Derived from B
class C : public B
{
public:
	//container
	std::vector<A*> objs;

	// Push n number of B'class objects in vector objs
	void pushObjs(int n)
	{
		for(int i = 1; i<= n; i++)
			objs.push_back(new B);
	}

	// override showChar()
	virtual void showChar() override{
		cout << "C::showChar called : " << endl;
		for (A* a : objs)
			a->showChar();
		cout << "END C::showChar" << endl << endl;
	}
	
	//Destructor
	~C(){ 
		cout << "BEGIN Destructor ~C call, objs delete" << endl;
		for (A* a : objs)
		{
			delete a;
		}
                objs.clear();
		cout << "END Destructor ~C" << endl << endl;
	};
};

int main()
{
	C obj{};
	// Create and push 3 objects from class B in obj.objs vector.
	obj.pushObjs(3);
	// Show pC virables of these 3 B class objects
	obj.showChar();

	cout << endl << "Releasing obj after program end :" 
		<< endl << endl;
}



C::showChar called : 
B::showChar() called : B
B::showChar() called : B
B::showChar() called : B
END C::showChar


Releasing obj after program end :

BEGIN Destructor ~C call, objs delete
Destructor ~B call , delete pC
Destructor ~A call
Destructor ~B call , delete pC
Destructor ~A call
Destructor ~B call , delete pC
Destructor ~A call
END Destructor ~C

Destructor ~B call , delete pC
Destructor ~A call
Last edited on
Override is used to check whether member functions actually override. And final is used to check whether member functions is overrided by other member functions, if so show error. They are good to use. And I need to use virtual destructor to prevent memory leak, before use it, ~B() can not sucessfully called when delete B object in objs.

1
2
3
4
for (A* a : objs)
		{
			delete a;
		}

And I see the compiler show warning message about undefined behavior when I don't use it. Delete object of abstract class with non-virtual destructor is undefined behaviour. The problems are not only memory leak but undefined behavior, thing get worsen.

There are what i learned from example. I have another questions to ask.

1
2
3
4
5
6
// In A class you have overloading of memberFunction()
	// So you put this line of code.
        // In this way, all the overloading functions of the base class A,
        // that you are not override in class B will attempt to be called if
        // B::memberFucntion() argument(s) don't match.
	using A::memberFunction;

What is the using directive actually do? Why is there no ambiguity between A::memberFunction() and B::memberFunction()? Why can doAThing(two) actually call B::memberFunction()?
Last edited on
What is the using directive actually do? Why is there no ambiguity between A::memberFunction() and B::memberFunction()? Why can doAThing(two) actually call B::memberFunction()?


Look "In class definition"

https://en.cppreference.com/w/cpp/language/using_declaration
Last edited on
I read that, member functions in class will override or hide the member functions introduced by using directive.
Topic archived. No new replies allowed.
Pages: 12