New to virtual methods

Aug 25, 2020 at 10:37pm
I am working through Sam's Teach Yourself C++ For Linux In 21 Days. Yes, it's an OLD book (Copyrighted 2000) but I HAVE it and the concepts seem relevant. I'm having a problem. I can't figure out this one. Today,I'm typing in a program from the book, but it's not giving me the correct output. pDog->Speak SHOULD be outputting Woof!, not Mammal speak! Why isn't it working?

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
//Listing 11.8 - Using virtual methods
//2020-08-25
#include <iostream>
class Mammal
{
   public:
      Mammal(): itsAge(1) { std::cout << "Mammal constructor...\n"; }
      virtual ~Mammal() { std::cout << "Mammal destructor...\n"; }
      void Move() const { std::cout << "Mammal moves one step.\n"; }
      virtual void Speak() { std::cout << "Mammal speak!\n"; }
   protected:
      int itsAge;
};
class Dog : public Mammal
{
   public:
      Dog() { std::cout << "Dog constructor...\n"; }
      virtual ~Dog() { std::cout << "Dog destructor...\n"; }
      void WagTail() const  { std::cout << "Tail wagging...\n"; }
      void Speak() const { std::cout << "Woof!\n"; }
      void Move() const { std::cout << "Dog moves five steps.\n"; }
};
int main()
{
   Mammal *pDog = new Dog;
   pDog->Move();
   pDog->Speak();
   return 0;
}

OUTPUT:

1
2
3
4
5
6
michael@caitlyn 11 $ ./listing11.8 
Mammal constructor...
Dog constructor...
Mammal moves one step.
Mammal speak!
michael@caitlyn 11 $ 
Aug 25, 2020 at 11:02pm
Your Move() function is not virtual.
Your Speak() function is not const-qualified in your base class, but is const-qualified in your sub class.
Aug 26, 2020 at 2:11pm
read the warnings
foo.cpp|20 col 12| warning: 'Dog::Speak' hides overloaded virtual function [-Woverloaded-virtual]
foo.cpp|10 col 20| note: hidden overloaded virtual function 'Mammal::Speak' declared here: different qualifiers (unqualified vs 'const')


to make it a compile time error
https://en.cppreference.com/w/cpp/language/override (c++11)
void Speak() const override { std::cout << "Woof!\n"; }
foo.cpp|20 col 26| error: non-virtual member function marked 'override' hides virtual member function
foo.cpp|10 col 20| note: hidden overloaded virtual function 'Mammal::Speak' declared here: different qualifiers (unqualified vs 'const')
Last edited on Aug 26, 2020 at 2:11pm
Aug 26, 2020 at 9:07pm
Thank you for pointing out that my base class Speak() method was not const. I corrected that in my program and it is running correctly now.
Aug 27, 2020 at 12:23am
its not that old books are totally wrong, they usually are not, so long as you understand that they can be wrong in places (due to language changes) and they can (and often do) present things that we have better ways to solve (language has added a ton since then).
It isnt that old. 3/4 of my books date from the late 80s/early 90s, because I never throw anything away I guess...

the stuff you are doing here is pretty much unchanged.
Last edited on Aug 27, 2020 at 12:23am
Aug 27, 2020 at 7:50am
Maybe this makes more sense than Sam's:

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
#include <iostream>
class Mammal
{
protected:
    int no_steps{-99};
    std::string sound{"???"};
    
public:
    Mammal(){ std::cout << "Mammal constructor...\n"; }
    virtual ~Mammal() { std::cout << "Mammal destructor...\n"; }
    virtual void Move() const { std::cout << "Moves " << no_steps << " steps.\n"; }
    virtual void Speak() { std::cout << sound <<'\n'; }

};

class Dog : public Mammal
{
public:
    Dog() { std::cout << "Dog constructor...\n";
        no_steps = 5;
        sound = "Woof woof";
    }
    ~Dog() { std::cout << "Dog destructor...\n"; }
    
    void WagTail() const  { std::cout << "Tail wagging...\n"; }
};

class Cat : public Mammal
{
public:
    Cat() { std::cout << "Cat constructor...\n";
        no_steps = 8;
        sound = "Meow meow";
    }
    ~Cat() { std::cout << "Cat destructor...\n"; }
    
    void Scratch() const  { std::cout << "Scratching ...\n"; }
};



int main()
{
    Mammal m;
    m.Speak();
    m.Move();
    
    Dog *pDog = new Dog;
    pDog->Move();
    pDog->Speak();
    pDog->WagTail();
    
    Cat *pCat = new Cat;
    pCat->Move();
    pCat->Speak();
    pCat->Scratch();
        
    delete pDog;
    delete pCat;
    
    return 0;
}


Mammal constructor...
???
Moves -99 steps.
Mammal constructor...
Dog constructor...
Moves 5 steps.
Woof woof
Tail wagging...
Mammal constructor...
Cat constructor...
Moves 8 steps.
Meow meow
Scratching ...
Dog destructor...
Mammal destructor...
Cat destructor...
Mammal destructor...
Mammal destructor...
Program ended with exit code: 0
Aug 27, 2020 at 7:52am
PS It doesn't make (common) sense to go to all the trouble of designing an inheritance scheme and then declaring a Mammal and then creating it as a new Dog.
Topic archived. No new replies allowed.