inheritance confusion

Hi guys,

assume I have a parent class which is supposed to be abstract in the sense that any running program would only run a child class that inherited from parent.

Some pseudocode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class parent{
    method A(){}  \\ empty method to be overwritten by childs
    method B(){
               \\ code block that stays the same for all childs
                A() 
               \\ code block that stays the same for all childs
}

class child : public parent{
     method A(){\\ code of the method}
}

int main(){

child testobjekt;
testobject.B();

}


I want to have many child classes with their own method A.

Is something like this possible? The thing is that method B in the parent class contains lots of constant code that would be the same for all childs so I do not want to have to copy'n'paste it everytime. But B in the parent class tries to call A which will only be implemented for the child classes..

Best,
PiF
Is something like this possible?

Yes!

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 <cstdio>

class base
{
public:
  // "= 0": this function is pure virtual and must be implemented by derived classes.
  virtual void f() = 0; 

  void g()
  {
    std::puts("starting base::g"); 
    f();          
    std::puts("ending base::g");
  }    
};

class derived1: public base
{
public:
  virtual void f() override { std::puts("derived1::f"); }
};

class derived2: public base
{
public:
  virtual void f() override { std::puts("derived2::f"); }
};

int main()
{
  derived1 d1; 
  d1.g();
}

https://godbolt.org/z/1n45hvzMz
Last edited on
Small point - virtual overriden member functions don't need virtual to be specified. It's sufficient to just mark the base function as virtual.

1
2
3
void f() override {
    std::puts("derived1::f");
}

https://en.cppreference.com/w/cpp/language/virtual explains several details with examples.
Also see chapters 16, 17, 18 of:
https://www.learncpp.com
Last edited on
Hi guys,

I had actually learned about virtual functions a couple of weeks ago, but seemed to have forgotten most of it again ~~
Goes to show that one should always write code when learning new programming concepts.

Thanks, I try it out!
I had actually learned about virtual functions a couple of weeks ago, but seemed to have forgotten most of it again

It may be useful to remember that C++ supports more than one programming paradigm. When doing object oriented programming, object methods are always virtual functions used from a pointer or reference.

If there's no virtual method or the object is being used directly, it's not an object, in the Object Oriented Programming's (OOP) view of an object.

I didn't want to clutter the main idea, so I'll add this here at the end. When talking about OOP in C++, it's natural to use the language's built in support of runtime or dynamic polymorphism, but there are ways of implementing compile time or static polymorphism, that have improved runtime performance, but are more complicated to read.
Last edited on
Make the function that needs to be overridden pure. In such a way, you are 'forcing' the object to be valid (compile time errors, if the pure function is not implemented!). Like 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
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
#include <iostream>
#include <string>

class Parent{
    public:
        Parent() = default;
        virtual void A() = 0; // make it a pure function so that all base
                              // classes must implement it. Otherwise, compile time error
        void B(){
            std::cout << "The parent class has the implementation of this method\n";
        }

        virtual ~Parent()=default;
    private:
    // private variables and functions
};

class FirstChild: public Parent{
    public:
        virtual void A() override{
            std::cout << "FirstChild has implemented A() in its own way\n";
        }
};

class SecondChild: public Parent{
    public:
        virtual void A() override{
            std::cout << "SecondChild has implemented A() in its own way\n";
        }
};

class ThirdChild: public Parent{
    public:
        virtual void A() override{
            std::cout << "ThirdChild has implemented A() in its own way\n";
        }
};

int main(){
    FirstChild first;
    first.B();
    first.A();

    std::cout << std::string(50, '=') << std::endl;

    SecondChild second;
    second.B();
    second.A();

    std::cout << std::string(50, '=') << std::endl;
    ThirdChild third;
    third.B();
    third.A();


    return 0;
}

Last edited on
Hi guys,

can you tell me why in the last line the method of the child class is executed?
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
#include <iostream>

class base_class {
    public:
    
        virtual void collect_measurements() const = 0;
    
        void run_simulation() const {
            collect_measurements();
        }

};

inline void base_class::collect_measurements() const {std::cout<< "Calling collect_measurements from base_class\n";}


class derived_class : public base_class {
    public:
    
        virtual void collect_measurements() const override{
            std::cout<< "Calling collect_measurements from derived class\n";
        }

};


int main () {
    
    derived_class d;
    
    d.run_simulation();                         // gives implementation of derived class as expected 
    d.base_class::collect_measurements();       // gives standard implementation as expected
    d.base_class::run_simulation();             // gives implementation of derived class... why??
    
}
Last edited on
You do call member function void run_simulation() const. It is non-virtual and member of the base_class. It does what it does.

You could call the very same function with d.derived_class::run_simulation(); and the result would be exactly the same. (The run_simulation() is a member due to inheritance.)

Calling the run_simulation() more explicitly does not affect what the implementation of that function does. The implementation is:
1
2
3
{
    collect_measurements();
}

and that calls a virtual member function.
Thanks Keskiverto,

then my way of thinking is wrong.
I interpret
 
d.base_class::run_simulation();

as "operating on an object of base_class" and thus base_class::collect_measurements() should be called.

On another note, my book says that calling of a virtual function as opposed to a nonvirtual one only shows different behavior when it is called from a reference or pointer of static type base_class.
As I do not use pointers or references this must be an error.

I remove the virtual keyword and check what happens in the d.run_simulation() case which resolved to the derived class above:
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
#include <iostream>

class base_class {
    public:
    
        void collect_measurements() const;
    
        void run_simulation() const {
            collect_measurements();
        }

};

inline void base_class::collect_measurements() const {std::cout<< "Calling collect_samples from base_class\n";}


class derived_class : public base_class {
    public:
    
        void collect_measurements() const {
            std::cout<< "Calling collect_measurements from derived class\n";
        }


};


int main () {
    
    derived_class d;
    
    d.run_simulation();   // gives base implementation (run_simulation was not overwritten
                          // so base_class::run_simulation() is called which then calls collect_simulation() in its scope.)   
        
}
I interpret d.base_class::run_simulation(); as operating on an object of base_class and thus base_class::collect_measurements() should be called.

You're operating on d, whose type is derived_class. You're just calling a particular member function by its full name, which is base_class::run_simulation.

On another note, my book says that calling of a virtual function as opposed to a nonvirtual one only shows different behavior when it is called from a reference or pointer of static type base_class.
As I do not use pointers or references this must be an error.
You are using references, just not explicitly. The implicit object parameter of base_class::collect_measurements is an lvalue reference to base_class const. That's why the call to collect_measurements on line 9 is dynamically dispatched according to the dynamic type of *this.
See: https://cplusplus.com/forum/beginner/284191/#msg1230640
Last edited on
my book says


Which book are you using?

A derived class with public inheritance has access to public and protected members of the class from which it is derived which in turn has access to its....

See
https://www.learncpp.com/cpp-tutorial/inheritance-and-access-specifiers/

and other chapters re classes.
Last edited on
I am still a bit confused by the logic. Let's move away from virtual functions again.

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_class {
    public:
    
        void collect_measurements() const;
    
        void run_simulation() const {
            collect_measurements();
        }

};

inline void base_class::collect_measurements() const {std::cout<< "Calling collect_samples from base_class\n";}


class derived_class : public base_class {
    public:
    
        void collect_measurements() const {
            std::cout<< "Calling collect_measurements from derived class\n";
        }

};


int main () {
    
    derived_class d;
    
    d.run_simulation();                         // gives base implementation
                                                      
}


Since run_simulation was not overwritten, d.run_simulation() is the same as d.base_class::run_simulation(). collect_measurements(), however, was overwritten and should be shadowing base_class::collect_measurements(). Therefore, even though collect_measurements() is called by a member function of the base class, I had expected it to resolve to derived_class::collect_measurements() as we are still operating on an object of type derived_class.

But it seems to be the case that member functions of the base class, even if they are called by an object of the derived class, only see the member functions of the base class, even if the latter were overwritten in the derived class. Is this true?
Last edited on
I am still a bit confused by the logic. Let's move away from virtual functions again.
Consider this:
1
2
3
4
5
6
7
int main()
{  
  derived_class const cd{}; 
  base_class const* pcd = &cd
  // calls base_class::collect_measurements because it's nonvirtual
  pcd->collect_measurements(); 
}
pcd has a static type of base_class const* and a dynamic type of derived_class const*. Since base_class::collect_measurements isn't virtual, the static type is used to choose the right function, and the base class version is selected.

The same reasoning applies to your code on line 9:
6
7
8
9
10
11
class base_class {
  // ...
  void run_simulation() const {
    collect_measurements();
  }
}
On line 9, collect_measurements() is shorthand for this->collect_measurements(). And this has a static type of base_class const* (because it's a member of base_class) and a dynamic type of derived_class const* (because run_simulation was called through a pointer to derived_class).

Since base_class::collect_measurements isn't virtual, the static type of this is used and the base class implementation gets called. If you wanted to use the dynamic type instead you'd need to make the function virtual.
Last edited on
Thanks mbozzi!

So if I have
1
2
3
4
int main () {
    derived_class d;
    d.run_simulation();                                                    
}

the collect_measurements() in
1
2
3
4
5
6
class base_class {
  // ...
  void run_simulation() const {
    collect_measurements();
  }
}

is actually the same as this->collect_measurements(), and since we call it from run_simulation(), a member of the base class, this is a pointer of static type base_class. Since I operate on an object of type derived_class, the dynamic type of this will be derived_class. But since collect_measurements is not virtual, this has no consequence and we obtain base_class::collect_measurements.

Now, if I wanted
1
2
3
4
int main () {
    derived_class d;
    d.run_simulation();                                                    
}

to give me derived_class::collect_measurements(), I could either make collect_measurements virtual, or simply overwrite run_simulation() in the derived class, right?
Last edited on
Yes, but to "overwrite" a non-virtual method is seldom a good option.
Last edited on
Besides, what you have shown could essentially be written:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

class base_class {
};

class derived_class : public base_class {
    void collect_measurements() const {
        std::cout<< "Calling collect_measurements from derived class\n";
    }
public:
    void run_simulation() const {
        collect_measurements();
    }
};


int main () {
   derived_class d;
   d.run_simulation();                                                   
}

If you don't call anything from base class nor require it as interface, then why have the base class at all?
Topic archived. No new replies allowed.