Pure Virtual Functions

From my book:

"Because you have declared Volume() as const, its implementation in any derived class must also be const. Remember that const and non-const varieties of a function with the same name and parameter list are different functions. In other words, a const version overloads a non-const version."

Doesn't his last statement contradict the statements before? He says there different types but then they can be overloaded? I also tried this and it doesnt work.

Also the use of a Pure Virtual Functions. One is forcing its derived classes to define it, if you do force them to define it that means that if they do not, they cannot call the base right?

The other one, that was not in my book that I think could be useful is that if you had a array of pointers to the base you could polymorphically use each derived class's function. For example consider 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 <string>
class Animal
{
protected:
    std::string m_strName;
 
    // We're making this constructor protected because
    // we don't want people creating Animal objects directly,
    // but we still want derived classes to be able to use it.
    Animal(std::string strName)
        : m_strName(strName)
    {
    }
 
public:
    std::string GetName() { return m_strName; }
    virtual const char* Speak()=0; //pure virtual
};
 
class Cat: public Animal
{
public:
    Cat(std::string strName)
        : Animal(strName)
    {
    }
 
    virtual const char* Speak() { return "Meow"; }
};
 
class Dog: public Animal
{
public:
    Dog(std::string strName)
        : Animal(strName)
    {
    }
 
    virtual const char* Speak() { return "Woof"; }
};

void Report(Animal &rAnimal)
{
    cout << rAnimal.GetName() << " says " << rAnimal.Speak() << endl;
}
 
int main()
{
   Cat cFred("Fred"), cTyson("Tyson"), cZeke("Zeke");
Dog cGarbo("Garbo"), cPooky("Pooky"), cTruffle("Truffle");
 
// Set up an array of pointers to animals, and set those pointers to our Cat and Dog objects
Animal *apcAnimals[] = { &cFred, &cGarbo, &cPooky, &cTruffle, &cTyson, &cZeke };
for (int iii=0; iii < 6; iii++)
    cout << apcAnimals[iii]->GetName() << " says " << apcAnimals[iii]->Speak() << endl;

return 0;
}


Something like that. So you can use that one little class to use all of the derived classes in a array and call their functions, at least the ones the overload in the base. Are these two the only uses?


Could anyone conform all the points I mentioned were true? Thanks!
Last edited on
Doesn't his last statement contradict the statements before? He says there different types but then they can be overloaded?

No, it's not contradictory.

If a const member function didn't take a different type than a non-const member function, it couldn't be overloaded. After all, that's what function overloading is. Selecting a function to call based on the type of the parameter(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
#include <iostream>

class Base
{
public:
    virtual double volume() const = 0 ;
};

class Derived1 : public Base
{
public:
    double volume() { std::cout << "Derived1::Volume\n" ; return 0.0 ; }
};

class Derived2 : public Base
{
public:
    double volume() { std::cout << "Derived2::Volume (non-const)\n"; return 0.0 ; }
    double volume() const { std::cout << "Derived2::Volume (const)\n" ; return 0.0 ; }
};

int main()
{
    // Derived1 d1 ;    // error: cannot instantiate abstract class.
    Derived2 d2 ;

    Base & d2_ref = d2 ;

    d2_ref.volume() ;  // calls the virtual method through the reference.
    d2.volume() ;
}
Last edited on

Can you please explain why that code gives two different outputs?

I'm even more confused?

So a const version overloads a non-const version? And can you please look over the other stuff I mentioned.

Thanks cire!
Wait so one calls the virtual and one calls the non-virtual because one is being called through reference and one is from member access operator?

Shouldn't both be const because the "const" overloads the non-const?

Why is that?
Last edited on
cire can you please reply :(
On line 29, a method is called through a base class reference. The only option through the base class reference is the const version of the function.

On line 30, we call a function through a derived class instance. This function is overloaded for both const and non-const objects. Because the object we're invoking the method with is not const, the non-const version is a better match than the const version. Again, that's how overloaded functions work. The best match is picked based on the parameter type(s).
At this point I feel like your ignoring my questions, cire.
If you have any reason where you feel I am rude or any reason where you dont want to answer my questions, tell me so I can improve!

Please reply!
At this point I feel like your ignoring my questions, cire.


I don't work here or get paid to answer questions, Anmol444. I am not always sitting here staring at the screen waiting for you to post your next question or response, nor do I find all of your questions/comments interesting and I certainly don't feel any sort of obligation to respond to all of them.

I don't find you rude, although I do find your "Please reply to me posts" 10 minutes after you post something to be a waste of bandwidth.
Alright sorry, cire.
Anmol444 wrote:
Also the use of a Pure Virtual Functions. One is forcing its derived classes to define it, if you do force them to define it that means that if they do not, they cannot call the base right?


A class can abstract - which means one cannot create an object of that type, because it contains a pure virtual function that by definition is not defined, and MUST be defined by derived classes. If a derived class does not define it - then it is a compile error.

If it is an ordinary virtual function, and the derived class does not define it, then the compiler will use the next available function that is defined in terms of working it's way up the inheritance tree from the derived class.

Anmol444 wrote:
The other one, that was not in my book that I think could be useful is that if you had a array of pointers to the base you could polymorphically use each derived class's function.


They don't have to be pointers to base, they would be pointers to the derived class objects - which is what you have in your code. It's just that pointers to derived are valid pointers to base.

This is a very handy feature of C++. Imagine you have a RPG where you have lots of Players, Enemies & Weapons, all in a big inheritance tree. Now you can declare an attack function which takes pointers to each 3 of these, and when you call the function you send the pointers of the concrete objects (that is the actual individual thing) . So now you don't have to write overloaded functions to accommodate every combination of objects. This particular example would probably work best with a Command (aka Action) Design Pattern.

The use of polymorphism like this is one situation where you do have to have an inheritance tree, otherwise one should probably prefer to make use of composition instead.

Another example which uses polymorphism is in a package that does unit conversions. I had an inheritance tree of units split up into their types - Angles, Distances, Areas, Temperature, Volume etc. I had 2 pure virtual functions in the base class - ToMetric & FromMetric, which took pointers to a Unit object. Each derived class redefined these functions to do their particular conversion. To do a conversion from one type to the other, convert to metric, then convert to the other type. For example, to go from Yards to Feet, convert Yards to Metres, then Metres to Feet. Sounds convoluted, but it is actually more efficient this way - if one had 10 units, then there is a need for 19 functions as opposed to 90. Btw boost has a whole conversion library which does mixtures of unit types, and being a professionally written library is vastly superior to my little example.

With your code, m_strName shouldn't be protected IMO. Rather it should be private, and you generally access it in the derived classes via an interface function in the base class. Although you can still use the initialiser list like you are doing now. You have an interface function called GetName, but instead you could have a member function that does the printing out. So you would call this function rather than using a get function in main().

We had a huge discussion about get & set functions here:

http://www.cplusplus.com/forum/lounge/101305/


Here are some of the more relevant parts:

http://www.cplusplus.com/forum/lounge/101305/5/#msg546461



Not all of what I said there was right (esp. the Send / Receive functions) - I saw the light a bit later - thanks to ne555 8+) here:

http://www.cplusplus.com/forum/lounge/101305/5/#msg546775


Also it might be educational to read the replies to what I said.

Hope this helps :)
Last edited on
@TheIdeasMan

What are you talking about, pointers to derived cannot point to base, only pointers to base can point to derived because when you try to use a pointer to derived to point to base, the pointer looks for all the derived data in base which there isnt.

Also what do you mean the next defined function, wouldn't it just use the virtual function inherited from the base?

Also for your second example, why is it more efficient this way? Are you referring to doing it with polymorphism or actually converting? I hope polymorphism. Also isnt there a need for just one? Why 19? I understand it could be 90 if you did not use polymorphism but why 19?

I made it protected so I could define functions in the derived classes that make use of it.

Alright I will read them thanks!


@Cire

Alright that makes sense.

Btw sorry, its just that you left me hanging, you gave my half of the answer but then thanks for filling it up xD
Makes sense now.
Anmol444 wrote:
What are you talking about, pointers to derived cannot point to base, only pointers to base can point to derived because when you try to use a pointer to derived to point to base, the pointer looks for all the derived data in base which there isnt.


Have a read of the polymorphism section in the tutorial - you will see what I mean with the example there.

Think of the RPG example, where there are lots of Players, Enemies, And Weapons in an inheritance tree. You could have a pure virtual function declaration like this:

virtual void Attack(CPlayer* ThePlayer, CEnemy* TheEnemy, CWeapon* TheWeapon) = 0;

Notice how generic the parameters are?

Then you have a call to the function with pointers to concrete objects:

Attack(pSoldier, pTrex, pMachineGun);

So now we don't need to have overloaded or multiple functions to handle every combination, of which there could hundreds.

Anmol444 wrote:
Also what do you mean the next defined function, wouldn't it just use the virtual function inherited from the base?


Imagine you have classes A,B,C,D,E where B is derived from A and so on until E is the most derived class. A has a virtual function. B provides a definition for it, D provides a new definition for it. When the function is called from class C, it runs the function defined in B, and when it is called from class E, the one in D is used.

This is handy for defining a function that applies to a whole branch of a tree. One of the main ideas about virtual functions is that one can provide specialisation of functions at various levels.

Anmol444 wrote:
Also for your second example, why is it more efficient this way? Are you referring to doing it with polymorphism or actually converting? I hope polymorphism. Also isnt there a need for just one? Why 19? I understand it could be 90 if you did not use polymorphism but why 19?


There a 2 functions for each type of unit - ToMetric & FromMetric, so if you have 10 units, that is 20 functions. But Metres doesn't need a ToMetric because it is the base Metric unit - Metres are Metres.

The number of functions has nothing to do with polymorphism, I could do the exact same thing in C or any other non OO procedural language. Polymorphism comes in because of the virtual functions - that's what it means. The beauty again is that we can declare one or a few virtual functions, rather than hundreds for each combination of objects. We can do this because of the generic nature of the parameters to the functions.

Anmol444 wrote:
I made it protected so I could define functions in the derived classes that make use of it.


Sure, that's really easy - I used to do that too. But it breaks encapsulation for the base class, and can cause major problems if requirements change in the future - it beaks any code in derived classes that relies on it. If you make all your data members private & provide sensible interface functions to them (don't do naive get / set functions - read the links above about that), then you can do quite a bit in those interface functions including checking & validation or some sort of calculation.

HTH
Topic archived. No new replies allowed.