why do i need polymorphism

Pages: 12
I can call a function that i want to call, and not to use virtual function. for example this code.

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
#include <iostream>
using namespace std;

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

class B : public A{
public:
	B();
	~B();
	void 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;
}

B::B(){
	
}

B::~B(){
	
}

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


and I use template to call what i want. The question is why somebody need to use polymorphism? what situation do i need to use polymorphism?
Last edited on
Polymorphism allows you to do this:

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
#include <iostream>
#include <vector>

class Base {
public:
    virtual void func() = 0;
};

class Derived1 : public Base {
public:
    void func() { std::cout << "Derived1\n"; }
};

class Derived2 : public Base {
public:
    void func() { std::cout << "Derived2\n"; }
};

int main() {
    std::vector<Base*> objs;
    
    objs.push_back(new Derived1);
    objs.push_back(new Derived2);
    objs.push_back(new Derived2);
    objs.push_back(new Derived1);

    for (Base* b: objs)
        b->func();

    // should perhaps delete the objects here
}

Output:
Derived1
Derived2
Derived2
Derived1

Last edited on
You've seen what @dutch illustrates.

Let me clarify what you're saying, @a00.

You've identified one of many types of compile time selection. One might think of it as a compile time polymorphism, but that ignores the underlying definition of the term.

What @dutch shows is a runtime selection by type, while being blind to the real type.

Your example, @a00, can't do that. Your code can make selection at compile time, which is a valuable technique and takes many forms, but it isn't a runtime selection while being blind to the type.

There are many situations, perhaps a majority, where runtime selection is required. I've also seen a great many designs where runtime selection wasn't important, but virtual objects were used anyway.

In @dutch's example, the base type could be a generic base for a command, while the derived types could be the detailed execution of that command. A single container is able to store these as base type pointers, but execute the specific commands in a loop while having no knowledge of the specific commands each represents.

There are a number of paradigms based on such notions.

On the other hand, one typical example where runtime polymorphism is used but probably not required is in rendering engines. I've seen more than a few which instantiate the renderer from a factory using a generic base renderer which is blind to the specific API (OpenGL/DirectX/Vulkan/Metal), instantiating the appropriate derived classes to implement the renderer for a particular graphics API.

Unfortunately that imposes a runtime penalty for every interface call to the renderer, and it isn't necessary. Hardly anyone really needs or wants to switch graphics API's at runtime quickly.

A way of implementing what you illustrate, @a00, is using policy based design. You almost illustrate it, but not quite. Policies are templates which can be applied to an interface template as parameters which become base classes. That English description is not clear, so let me illustrate:

1
2
3
4
5
template <typename T> 
class InterfaceClass : public T
{
 // various template code here
};


This shows that the parameter becomes the class from which the InterfaceClass is derived, giving rise to the opportunity to impose selected behavior upon the interface at compile time. The technique can be nested, so that policies build up from several options selected for the implementation.

This is also inverted in design. In virtual base classes, the interface is in the base which is overriden by virtual functions in the derived classes which are called by a pointer to member function mechanism hidden within the class structure (the vtable).

In policy based templates, however, the interface is the most derived class, and the implementation that is selected appears in the base classes which it operates, and access those functions without the need for virtual function calls, vtables or pointer to function mechanisms.

Of course, this obviates runtime selection. The policy is built as a complex type at compile time. While one could instantiate many forms of them, they could not be contained as a common base type as easily as virtual base class designs.

There's an old book by Alexandrescu (2001) which covers policy based template designs, which is related to but not actually the CRTP (curiously repeating template pattern).

Bottom line, here, is that while you have a point in your question, it isn't a rebuke of virtual objects. It is the other side of that subject.

Last edited on
Polymorphism is a useful tool for minimizing header bloat and decoupling code. You can chop up your code easily into modules using this system, and those modules could be accessed through a singleton (singleton is a naughty word, but I don't see how you can write a big project without at least one). Using polymorphism to decouple code is called an observer pattern in the Gang Of Four I believe, and all the patterns are designed for reducing coupling, which is important for a project larger than a single file.

Templates will very easily make header bloat happen if you use it in places that don't make sense. For me, templates should only be used if they can make your code shorter, like for removing copy-paste due to multiple types using the same function.

But, I don't see why you need OOP or templates, why don't you use C and use functions and structs? Everything you can do in C++, I can do in C, or Assembly or Python or Rust, etc etc. Like whats the point??? 🤷
Everything you can do in C++, I can do in C, or Assembly or Python or Rust, etc etc. Like whats the point??? 🤷


Well, this risks hijacking the thread, but....

Sure, entire operating systems are written in C, and those are among the most ambitious targets made.

However, that it can be done isn't the point.

Consider in C the simple integer and float (and double). If you write in assembler you know full well that if you use floating point instructions on an integer, you get gibberish. Likewise, using integer instructions on floats or doubles produces largely unusable results. The programmer makes the selection, because in assembler the only real difference between integers, floats and doubles is the format of the bits.

In C, however, the selection is automatic by type. The type used makes the appropriate selection of the processor's instructions, and I've not seen it make a mistake on this selection on 40+ years of software development. I submit that this behavior, the selection of an instruction or process by type is the behavior of an object.

You know the cliche, "If you have a hammer, all your problems look like nails." What if the problem is a screw? Would the hammer likely produce acceptable results? Probably not. Yet, who among us hasn't flipped a screwdriver the "wrong way around" to pound in a small nail?

It is common to all human thought that a strong associate exists between things and processes. We don't drive a bicycle the way we drive a car. Even the word "drive" seems out of place in that phrase. For every thing we do we have strong associations between knowledge and objects, even theoretical ones.

You don't use trigonometry to solve chemical equations. There no reason to apply quaternion algebra for simple addition.

In C, the family of fread/fwrite/fclose (and related functions) either require or return a FILE *. Other than fopen itself, there's hardly any use for these functions without a FILE *. It is a structure filled out by open, used by all the others, and basically deconstructed by fclose. These are very old, yet they outline what is a loosely object like collection.

Therein is the point.

Where human thought commonly requires the association of objects and behaviors, it should not be puzzling that language would reflect that, as in the case of inappropriate phrasing with "drive" with "bicycle". There is leverage to be gained.

Write a GUI Windows application of some ambition in C, the way I did it back in the 80's, learning from Petzold's text. Then, grab a copy of either Qt or WxWindows and write the same application.

It will take you only that experiment to clearly demonstrate why OOP matters.

If that experiment doesn't make it clear, it never will be.

Of course, Java and C# fans would argue they have better support for GUI applications than either Qt or WxWindows (or MFC, or ATL or any number of frameworks of the past).

Then, try to find a product of ambitious design, like Photoshop, 3DS Max, Revit, AutoCAD, Inventory, Mudbox, Rhino, Cinema4D, UE4, Unity, or any number of applications from spreadsheets to SQL engines, written in C# or Java. The list will be comparatively small.

Then, find them in C.

The list will be older products, likely not for more than one operating system, not easily ported between operating systems, and quite probably just operating systems.

Python finds a place among casual programmers from other professions. They don't have time to master the complexity (and nastiness) of C++ or C. They may just as much prefer Java or C# (I've seen all 3), but they share something in common. They are not, typically, among the primary products in demand.

That has its place, so I'm not saying such software or those languages are inferior. They are, however, inferior for a certain type of application requirements. C++ isn't a language for everyone. Certainly C even less so.

Yet the notion of OOP, which isn't all that well defined or clear, brings within it indispensable leverage. The originator of the part of the term "Object" wasn't even clear on what it has come to mean, and it means to many different things that aren't even about objects themselves.

That goes back to the notion of C's integers selecting behavior based on type. That isn't a class, and there's nothing of a template. There's no language feature involved, because it is otherwise entirely opaque to the programmer. There's also no leverage available to apply it elsewhere by choice. C has no such feature. C++ does. That's why one can fashion a library of vectors, matrices, quaternions and such to operate linear algebra in a fashion similar to their simpler counterparts. Certainly 3D graphics applications have been written in C, but like writing a Windows GUI in C, it takes a lot more work.

a = b * c;

Seems like an obvious statement. Without types declared, however, it is a fragment easily assumed to represent either integers or floats. Yet, this could be a rotation of vector b by quaternion c, producing a view in vector a according to a camera's position.

To do that in C would require something like,

rotate( a, b, c );

...and so what? It would work, certainly, where the function does the same thing to the same data.

Well, not so fast to assume so. In Eigen, the statement a = b * c may not do what it looks like it's doing at first. Where b and c may be defined as n dimensional matrices and vectors, the resulting transformation might be called with a function in C, as was the rotate function, but that's not what Eigen does. The operator * fires an instruction generator, but does not perform the multiplication of the vector by the matrix. Instead, it encodes what that instruction is, along with the parameters, for transport through the =, such that then, in the assignment operator a runtime optimization can be chosen for whatever chain of operations have been concatenated for the most efficient processing. It may be expressed, in a different line, as a = (b * c) * d, where now the various * operators chain instructions together, as required, to feed those instructions to the assignment operator for threaded scheduling of the solution.

Not something you can create in C# or Java, certainly not Python or Perl, C or Fortran. D can do it.

...but who knows D?

R might. I haven't checked.

This is not to imply the objects are the answer to programming problems, and certainly a student of the language should realize that classes aren't always the right thing to build.

The real point is that as the language evolved over 30 years there accumulated a number of leveraged features which incrementally follow the way humans think. It is far from complete, and may have more to go than how far it has come.


I had to put the emoji to make it clear it is a joke. (it was a bad one, I know, I was tempted at also writing "Like whats even the point of even programming?")

Overall I think arguing over programming features is like arguing about programming languages (especially since C++ is just a melting pot of programming styles). Which is like arguing about politics, nobody wins. And the joke is that I am saying "WHY USE A C++" on a C++ board, and reflect that on OP for saying "WHY USE FEATURE".

ha ha i am very funnd
Last edited on
reflect that on OP for saying "WHY USE FEATURE"


I ask why use polymorphism, because I just need to know why, since sometimes I need to choose template or polymorphism. And i don't know which is better for me to use, in what situation, and so on. Knowing why use polymorphism maybe can help me to determined what things to do, to choose which.

I thank your attentive reply, I will take it seriously.
Last edited on
what situation do i need to use polymorphism?


which to use template or polymorphism in what situation?
In what situation it better for me to use polymorphism?
In what situation it better for me to use template?
Last edited on
@a00, I hope you've enjoyed the exchange.

Polymorphism, particularly when you need blind access to the derived behaviors. It comes up less than you might assume, though. Wait to make a class virtual until you have little choice. That's not because they are bad to use, but because the design will tell you what is required as you gain experience.

Templates when you need to adapt to types.

...and there's no reason you can't combine them, there are polymorphic templates. std::bind may be implemented by mixing the two. Templates can derive from non-template base classes, which may or may not be virtual. Sometimes you write a function in a template class only to realize it doesn't use anything the template adapts to, making it a candidate for pushing into a non-template base class to help avoid bloat.

std::swap is a good, simple example of templates, but so are all all of the containers from vector to the underused deque. Templates lend themselves to making libaries. Note, too, that swap is a template function, not a class. It is a powerful concept embodied in the STL, just so the function can be applied to any type (because it isn't the member of a class).

@poteto, I actually got the joke part, but in a public forum for the OP I thought it would reasonable banter. I've seen your posts around and it's fairly clear you're no lightweight. When you brought in assembler, I knew you were not being serious.
Last edited on
You need polymorphism for cases like this, for 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
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
#include <iostream>
using namespace std;

class A{
public:
	A();
	~A();
	void memberFunction();
	// Simply call memberFunction
	void callMemberFunction(){this->memberFunction();}
private:
};

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

template<class t>
void doAThing(t);

int main(){
	A one;
	B two;
	
	cout << "What happen?!" << endl;
        doAThing(one);
	doAThing(two);
	
	system("pause");
	return 0;
}

template<class t>
void doAThing(t one){
        // I change code here
	one.callMemberFunction();
}

A::A(){
	
}

A::~A(){
	
}

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

B::B(){
	
}

B::~B(){
	
}

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


And how to deal with this problem using polymorphism.

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
#include <iostream>
using namespace std;

class A{
public:
	A();
	~A();
	virtual void memberFunction();
	// Simply call memberFunction
	void callMemberFunction(){this->memberFunction();}
private:
};

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

template<class t>
void doAThing(t);

int main(){
	A one;
	B two;
	cout << "Now it works!" << endl;
        doAThing(one);
  	doAThing(two);
	
	system("pause");
	return 0;
}

template<class t>
void doAThing(t one){
        // I change code here
	one.callMemberFunction();
}

A::A(){
	
}

A::~A(){
	
}

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

B::B(){
	
}

B::~B(){
	
}

void B::memberFunction(){
	cout << "from B" << endl;
}
Last edited on
why somebody need to use polymorphism?
what situation do i need to use polymorphism?

The "Why"-question implies "I don't use X. Therefore, nobody needs X." Not a best possible way to start a conversation.

"What situation" / In what situation / When / Where is much better phrasing.


In order to choose between A and B one should understand both. What they allow? What they require? What they offer? What they prevent?

Perhaps you can implement something with either feature. The hammer can be used for many things, if you are skilled with it. However, whenever your hammer-based design starts to look large and complex, you should start to ask: Could this become simpler by any other method?
You want practical case with the same problem:

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
#include <iostream>

class CBox // Base class
{
public:
    // Function to show the volume of an object
    void showVolume() const
    { std::cout << "Volume is " << volume() << std::endl; }
    
    // Function to calculate the volume of a CBox object
    double volume() const
    { return m_Length*m_Width*m_Height; }
    
    // Constructor
    explicit CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0)
    :m_Length {lv}, m_Width {wv}, m_Height {hv} {}
protected:
    double m_Length;
    double m_Width;
    double m_Height;
};

class CBoxSpecial : public CBox // Derived class
{
public:
    // Function to calculate volume of a CBoxSpecial
    // allowing 15% for packing
    double volume() const
    { return 0.85*m_Length*m_Width*m_Height; }
    
    // Constructor
    CBoxSpecial(double lv, double wv, double hv): CBox {lv, wv, hv} {}
};

int main()
{
    CBox myBox {2.0, 3.0, 4.0}; // Define a base box
    CBoxSpecial myBoxSpecial {2.0, 3.0, 4.0}; // Define derived box - same size

    myBox.showVolume(); // Display volume of base box
    myBoxSpecial.showVolume(); // Display volume of derived box
    
return 0;
}



Volume is 24
Volume is 24


But this is not what you want. You want when you call myBoxSpecial.showVolume() base class CBox function to use volume() from CBoxSpecial variant instead CBox::volume().

So you can make volume() function virtual and problem will disappeared

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
#include <iostream>

class CBox // Base class
{
public:
    // Function to show the volume of an object
    void showVolume() const
    { std::cout << "Volume is " << volume() << std::endl; }
    
    // Function to calculate the volume of a CBox object
    virtual double volume() const
    { return m_Length*m_Width*m_Height; }
    
    // Constructor
    explicit CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0)
    :m_Length {lv}, m_Width {wv}, m_Height {hv} {}
protected:
    double m_Length;
    double m_Width;
    double m_Height;
};

class CBoxSpecial : public CBox // Derived class
{
public:
    // Function to calculate volume of a CBoxSpecial
    // allowing 15% for packing
    virtual double volume() const
    { return 0.85*m_Length*m_Width*m_Height; }
    
    // Constructor
    CBoxSpecial(double lv, double wv, double hv): CBox {lv, wv, hv} {}
};

int main()
{
    CBox myBox {2.0, 3.0, 4.0}; // Define a base box
    CBoxSpecial myBoxSpecial {2.0, 3.0, 4.0}; // Define derived box - same size

    myBox.showVolume(); // Display volume of base box
    myBoxSpecial.showVolume(); // Display volume of derived box
    
return 0;
}



Volume is 24
Volume is 20.4


P.s. This is slightly modified example from "Ivor Horton’s Beginning Visual C++® 2013"

P.p.s Many times I see people asking "Why I need this or that?". Never ask this question aggressively. The truth is you do not need anything except the machine code. If you can write programs in 0 and 1 - you are welcome. But we are people, not machines, so we need programming-friendly tools. These resources are created for your convenience, and you do not have to criticize them simply because you do not understand them in depth. You are not obliged to use them too. No matter what you use, it is important that your program meets the goal you have set - it works without any errors and with sufficient speed. But the problem comes when you are obliged because of any circumstances reading a foreign code. Other people may have a different opinion, so it is good to understand at least the means they use. For example, I don't like OOP at all, and I prefer to avoid it - but just because I do not like it, I have to learn it.
Last edited on
@poteto @keskiverto

I think you've both misunderstood the OP's question. I don't think the OP was trying to be dismissive of the feature, or trying to imply there's no need for it. I think the OP was genuinely asking for advice about when polymorphism is useful, and in what sort of situations you might want to use it in preference to templates.

That's a perfectly reasonable thing to ask - this sort of thing may have been intuitive to you the first time you encountered it, but it certainly isn't to everyone.

I think we can afford to be a little more charitable about the intentions of posters here...

My answer to the OP would be that polymorphism is useful when you want to be able to treat objects as if they were of a generic type, with the same interface, but also to have those objects exhibit different behaviour based on what specific types they are.

This is demonstrated by the posts made by @dutch and @Emil Enchev
@dutch You put him right in the deep :-)

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
#include <iostream>
#include <vector>

// This is abstract class.
class Base {
public:
    // 1. Base::func() is defined as a 'pure' virtual function, signified by '= 0'
    // 2. A class that contains a pure virtual function, like this one,
    // is called an abstract class. 
    // 3.It’s called abstract because you can’t define objects of a class
    // that contains a pure virtual function.
    // 4. However, you can define pointers and references of an abstract class type.
    // 5. An abstract class exists only for the purpose of deriving classes from it!
    virtual void func() = 0;
    
    // You must make destructor of Base abstract class virtual. Now, the destructors in all 
    //the derived classes are automatically virtual, even if you don’t explicitly
    //specify them as such. Of course, you’re free to specify them as virtual if 
    //you want the code to be absolutely clear. This is very important step because
    //if you don't make Base destructor virtual you will have problem with 
    //the proper release of your objects. You can test it, make destructors not virtual,
    //and see result from releasing of @dutch vector release
    virtual ~Base()
    { std::cout << "Base destructor called" << std::endl; }
};

class Derived1 : public Base {
public:
    // 6. If a class that is derived from an abstract class does not define 
    // a pure virtual function that is inherited from the base class, then 
    // it is also an abstract class.
    // 7. In Derived1 and Derived2 you define func(), so they are not
    // abstract classes.
    virtual void func() override { std::cout << "Derived1\n"; }
    
    // Derived1 destructor
    virtual ~Derived1()
    { std::cout << "Derived1 destructor called" << std::endl; }
};

class Derived2 : public Base {
public:
    virtual void func() override { std::cout << "Derived2\n"; }
    
     // Derived2 destructor
    virtual ~Derived2()
    { std::cout << "Derived2 destructor called" << std::endl; }
};

int main() {
    // You can define objects from Derived1 and Derived2
    // because they are NOT abstract classes
    Derived1 d1Obj;
    Derived2 d2Obj;
    
    std::cout << "call func() from  Derived1" 
        << " and Derived2 objects:" << std::endl << std::endl;
    d1Obj.func();
    d2Obj.func();
    std::cout<<std::endl;
    
    // You can't define objects from Base class
    // because it is abstract.
    //Base bObj;           // uncomment for error.
    
    // But you can define pointers and references to Base    
    Base* p_bObj{};
    
    std::cout << "call func() for Derived1 and" 
        << " Derived2 objects from Base class pointer:" << std::endl << std::endl;
    
    p_bObj = & d1Obj;
    p_bObj->func();
    
    p_bObj = & d2Obj;
    p_bObj->func();
    
    std::cout<<std::endl;
    
    std::cout << "@dutch example" << std::endl << std::endl;
    // Nice @dutch example where he show you
    // how to push_back different class objects in 
    // vector using Base class pointer.
    std::vector<Base*> objs;
    
    objs.push_back(new Derived1);
    objs.push_back(new Derived2);
    objs.push_back(new Derived2);
    objs.push_back(new Derived1);
    
    for (Base* b: objs)
        b->func();

    // should perhaps delete the objects here
    
   std::cout << std::endl << "Clear @dutch vector: " << std::endl << std::endl;     
   for (Base* b: objs)
   {
     delete b;
   }
   objs.clear();
  
  std::cout << std::endl << "After a program end, d2Obj and d1Obj"
     <<" was released" << std::endl << std::endl;
}


Do you see this part from result:


Clear @dutch vector: 

Derived1 destructor called
Base destructor called
Derived2 destructor called
Base destructor called
Derived2 destructor called
Base destructor called
Derived1 destructor called
Base destructor called


Now try to delete virtual keyword in front of ~Base() destructor and see result again, i.e. from

virtual ~Base()

make it simply

~Base()

Result will be:


Clear @dutch vector: 

Base destructor called
Base destructor called
Base destructor called
Base destructor called


That is, if your abstract class destructor ~Base() is not virtual, you will not be able to free your objects properly in vector objs.

As I said @dutch pushed you straight into the deep. I like that ;-)

P.s. And do not worry. C++ is difficult language for learning. Even if Bjarne Stroustrup tell you that he is PROFICIENT in C++ you can easily laugh at him and he probably will not be offended, but he will consider that you know something about this programming language above average programmer. Do not be ashamed to ask questions if something is not clear to you.
Last edited on
And the off the cuff answer: you may not need these things.
- everything can be programmed in assembly language which does not really even have structs or any other complex user defined objects at all (you can group things yourself, but its not the same thing). It also takes a week to rewrite a page of C++ in assembly if you do it right. Its not cost effective to spend the time to do it for most things.

That same idea scales up to C ... you can do anything in it, but it may be a bit challenging to express the ideas there. Scale on up to C++ ... the ideas are easier to express with the rich set of tools we have, and that makes it easier to write, easier to read, easier to debug, less code needed, and so on.

But you may not need it. Over-use of OOP tools, esp random inheritance syndrome, are worse than writing it in C to begin with! What a programmer needs is to understand what the tools he has ARE, and WHEN to use them, and WHY. That is the gist of what you are asking, I think, and the answers are up there ^^ if a little jumbled, but these answers are not going to beat out experience. One of the best things that can happen to you as you learn your tools is to fail badly. Nothing will teach you the WHY behind some of these tools like trying to do it without them and making a giant mess of it, then seeing it (or something similar) done the right way. Your mind will connect what you are designing now to the mistake you made before and you will remember and understand the better approach and you will use it. I don't know any shortcuts that teach the ideas as deeply. Yes, you can (and should) listen to experts on why to do what and when and where, and it helps, but screwing it up for yourself brings far more understanding to most people :)
Emil Enchev
You need polymorphism for cases like this, for example:
And how to deal with this problem using polymorphism.

It's seem like the this pointer is the same, but memberFunction is changed.
Last edited on
Template don't work anymore. so in line 53, I use polymorphism. The goal is to use A::memberFunction(int); This is code:

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
#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();
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);
//	doAThingTwo(three);
	doAThingThree(three);
	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
Emil Enchev
The volume() in line 8 refer to virtual double volume() const so that I can count Box's and SpecialBox's volume. Nice.
Last edited on
MikeyBoy
This is what I want to express, thank for clarification.
Emil Enchev
It shows me the big picture about polymorphism. And I trie to make base destructor not virtual, i get undefined behavior.
Pages: 12