inheritance and polymorphism

Hello,

I have a general question about inheritance and polymorphism.

To start right away, here is my minimal working 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
#include <iostream>

using std::cout;
using std::endl;

class Parent_a
{
   public:
      Parent_a(): a(1) { }
      void set_a(int a_v) {a = a_v;}
      int  get_a() {return a;}
      virtual int get_b() {}
      virtual int get_c() {}
   private:
      int a;
};

class Child_b: public Parent_a
{
   public:
      Child_b(): b(2) { }
      void set_b(int b_v) {b = b_v;}
      int  get_b() {return b;}
   private:
      int b;
};

class Child_c: public Child_b
{
   public:
      Child_c(): c(3) { }
      void set_c(int c_v) {c = c_v;}
      int  get_c() {return c;}
   private:
      int c;
};


int main()
{
   Parent_a pa;
   Child_b  cb;

   cout << "Parent_a.a: " << pa.get_a() << endl;
   cout << "Child_b.b:  " << cb.get_b() << endl;

   cout << "Child_b.a:  " << cb.get_a() << endl;

   Parent_a* p_pa_b = &cb;
   cout << "p_pa_b->b:  " << p_pa_b->get_b() << endl;//needs virtual get_b() decl. in Parent a

   Child_c cc;
   Parent_a* p_pa_c = &cc;
   cout << "p_pa_c->b:  " << p_pa_c->get_b() << endl;
   cout << "p_pa_c->c:  " << p_pa_c->get_c() << endl; //needs virtual get_c() decl. in Parent a
   Child_b* p_pb_c = &cc;
   cout << "p_pb_c->c:  " << p_pb_c->get_c() << endl; //does NOT need virtual get_c() decl. in Child_b because Child_b inherits virtual get_c() from Parent_a 

   cout << "p_pa_b->c:  " << p_pa_b->get_c() << endl; //garbage result

   return 0;
}

------------------------------------------------------------------
The code is working and the output is:
Parent_a.a: 1
Child_b.b:  2
Child_b.a:  1
p_pa_b->b:  2
p_pa_c->b:  2
p_pa_c->c:  3
p_pb_c->c:  3
p_pa_b->c:  4197548


I have two questions about this:

1) Does the base class need to declare all the functions I want to use by polymorphic binding. I.e. if Child_b evolves and gets a new function I have to declare the same function in Parent_a in order to use it via polymorphic binding?

2) While point (1) may be just an inconvenience, I am really concerned about the last result: as the virtual get_c() function is inherited all the way from Parent_a to Child_b to Child_c there is no need to define it in Child_b. But if it is called via p_pa_b->get_c() the result is, of course, garbage: c was never defined. But the run-time binding prevents any compiler warning!
Is this a natural danger that comes with the polymorphic binding or did I understand it wrong?

Thanks in advance.
Last edited on
1) Does the base class need to declare all the functions I want to use by polymorphic binding
Yes.
if Child_b evolves and gets a new function I have to declare the same function in Parent_a in order to use it via polymorphic binding?
No, the child can start its own hierarchy that has more stuff than its parent.

However, polymorphism only works when calling methods via pointers or references.

Specifically, polymorphism doesn't work when calling methods directly, and it does not apply to members (data).
Hi DMX,

The way you're asking these questions makes me think that you may find the "interface segregation principle" useful. The basis of this principle says that you should try to split your interfaces into single responsibility classes that can then be combined for an ability to provide specific and discrete functionality for inheritors.

Consider a contrived example, where you're creating a class to represent a multi-function printer.

A beginner's approach may be the following:

1
2
3
4
5
6
class MultifunctionPrinter : public IMachine
{
void print(Document* document) override { //implementation }
void scan(Document* document) override { //implementation }
void fax(Document* document) override { //implementation }
};


where IMachine is an abstract interface that declares the base functionality.

1
2
3
4
5
6
class IMachine
{
void print(Document* document) = 0;
void scan(Document* document) = 0;
void fax(Document* document) = 0;
};


That looks well and good for a multi-purpose printer, and if we needed to add functionality to the printer, we'd just stick another function in the IMachine class and override it in the multi-function printer. Sounds reasonable right?

Well, the problem becomes (and I think your question kind of alluded to this), that you then have to continue to add a bunch of functionality to a polluted base class. What if we wanted to inherit from IMachine but only implement a printer with scanning and printing? Or just faxing and printing? Or just faxing and scanning? Or just scanning? Or just printing? When we inherit from IMachine we get a ton of extra functionality that we don't need!

A better approach is to create multiple abstract interfaces and combine them for a more flexible combination:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class IPrinter
{
void print(Document* doc) = 0;
};

class IScanner
{
void scan(Document* doc) = 0;
};

class IFaxer
{
void fax(Document* doc) = 0;
};


The to make a MultiPurposePrinter we can combine these via multiple inheritance:

1
2
3
4
class MultiPurposePrinter : public IPrinter, IScanner, IFaxer
{
// Overrride print, scan and fax.
};


But if we just wanted a printer that could print and fax:


1
2
3
4
class PrinterWithFax : public IPrinter, IFaxer
{
// Overrride print and fax.
};


Or a scanner with the ability to fax:


1
2
3
4
class ScannerWithFax : public IScanner, IFaxer
{
// Overrride scan and fax.
};


You can see that this code is much more flexible and keeps the separation of your base classes much cleaner.

HTH,

Aaron
Topic archived. No new replies allowed.