Virtual functions

Hello,

I need some help on virtual functions. If we declare the following class:
1
2
3
4
5
6
7
8
9
10
class Animal {
public:
    virtual string sound() {
        return "animal sound";
    } };
class Dog : public Animal {
public:
    string sound() {
        return "bark";
    } };


and call from main():
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
Dog dog;
Animal* animal = &dog;

cout << dog.sound() << animal->sound() << endl;

//gives output "barkbark"

// where as

Animal animal_2 = dog;

cout << animal_2.sound();

//output "animal sound"

while 


Animal& animal_3 = dog;

cout << animal_3.sound();

//output "bark"

//WHY do animal_2 and animal_3 give different output??? 


So what's really the thing with virtual functions? As far as I understand it gives you the opportunity to store an address of a daughter-class in a mother-class pointer, but still call the daugther-class member function. Correct?

And why is the output different in my animal_2 and animal_3 example?
So what's really the thing with virtual functions? As far as I understand it gives you the opportunity to store an address of a daughter-class in a mother-class pointer, but still call the daugther-class member function. Correct?
The pointers are stored in a virtual function table. Actually an array where each constructor [re]places the addresses of the virtual functions.

And why is the output different in my animal_2 and animal_3 example?
animal_2 contains the [partial] copy of the content of dog (not the virtual function table), while animal_3 is the refernce to dog.
 
Animal animal_2 = dog;

This constructs an Animal object from a Dog object. Since animal_2 is an Animal object and not a Dog object calling sound() on this object will call the Animal::sound() member function. It's called object slicing because only the Animal parts of the Dog object will be copied which is usually not what you want. To avoid this you might want to disable copying of the Animal class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Animal {
public:
	Animal() = default;
	Animal(const Animal&) = delete; // disable the copy constructor
	Animal& operator=(const Animal&) = delete; // disable the copy assignment operator
	
	virtual string sound() {
		return "animal sound";
	}
};

...

Animal animal_2 = dog; // error: use of deleted function ‘Animal::Animal(const Animal&)’ 


Thank you @coder777 and @Peter87.

I didn't quite catch why there is a difference between

Animal& animal_3 = dog;

and

Animal animal_2 = dog;

however?


Also,

I assume this is related to virtual table, which is stored in a virtual pointer...? Any good explanation of this?
Last edited on
animal_3 is a reference to an object. When you call a virtual function it will look up the correct function using the dynamic type of the object that the reference is referring to (not the static type of the reference). The pointer example (Animal* animal = &dog;) works the same way.

animal_2 does not refer to another object. It is an object, and its type is Animal, so that is why it will just call Animal::sound().
Last edited on
Thanks @Peter87!

If Animal::sound() is not declared virtual, will it always call Animal::sound() if Animal is the type of the pointer/reference (i.e. it will follow the type the pointer/reference it is declared as, rather than the type of the object it is assigned to?)

For example (Animal::sound not virtual):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Dogx dog;
    Animal* animal = &dog;
    
    Animal& animal_2 = dog;
    
    cout << dog.sound() << endl << animal->sound();
    
    cout << animal_2.sound();

//output:

//bark 
//animal sound
//animal sound 



Yes, that's correct.
Topic archived. No new replies allowed.