Skip to main content
gamedev.net
🔒 Locked

=0 Question

Started by Drezard Jan 17, 2007 at 8:51 PM 10 replies 1.1k views
Original Post
Drezard
Drezard
Hello, Im reading a book called C++ Game Engine Programming (Amazing book) and in the code where they declare functions inside of classes they put =0 on the end. Like this: Code: virtual bool IsRunning(void) =0; (if sorry if its illegal to post this code but its in the interest of knowledge) Why do they do that? Also, It doesnt explain very well but what does the Virtual at the start mean? - Cheers, Daniel
blakedev
blakedev
A virtual function followed by =0 is a pure virtual function. It means that you must force derived classes to override that function. Otherwise, it make your class abstract, and cannot by instanced.
jouley
jouley
You're jumping into one of the important parts of C++ - inheritance. To supply brief answers (in reverse order, because it's more logical that way):
2) virtual is a keyword that says to the compiler "Hey, compiler, this function might be implemented differently in classes that derive from this one."

1) That "= 0" at the end says to the compiler "Hey, compiler, this function MUST be implemented differently in classes that derive from this one."

To illustrate these things, let's have a simple example. To make it fun, let's make an Animal class. Animals are fun, right? It might look something like this:
class Animal{public:                    Animal( );    void            Speak( );    void            Move(float fDistance);}
Pretty simple, right? There'd be more to it than that (size, age, name, etc.), but this is good for an explanation.

It's clear what Move should do, but what about Speak? Different animals make different noises. Say you wanted to make a Dog class. You could start all over, and reinvent the Animal wheel, OR you could just make Dog inherit from Animal. First, you have to let Animal know that it's inheritable. That's the answer to your second question, and it goes like this:
class Animal{public:                    Animal( );    virtual         ~Animal( );    virtual void    Speak( );    virtual void    Move(float fDistance);}
Go back and read that as the compiler would. "Hey, compiler, Speak may be implemented differently in classes that derive from this one." Then, your Dog class would look like this:
class Dog : public Animal{public:                    Dog( );    void            Speak( );    void            Move(float fDistance);}
Speak could then have a different implementation (void Dog::Speak( ) { std::cout << "Woof! Woof!" << std::endl; }). This brings up a good point. What should Animal's Speak function do? There's no way to tell what it should sound like - Chirp? Tweet? Meow? Booga-Booga? This is where that "= 0" comes into play. You tell the compiler that ever class that inherits from Animal absolutely must implement Speak. You'd declare it in Animal like this:
virtual void        Speak( ) = 0;
It basically means that there is no definition for it, so derived classes had better have one.

That answers those two important questions about inheritance, but you should have many more. To answer them (and other questions RE: C++), I send you here, in which the inheritance fun starts in section 19.

Let me know if I need to clarify anything, and best of luck!
-jouley

[Edit: Added virtual destructor to Animal (version 2). If your class is inheritable, its destructor must be declared as virtual.]

[Edited by - jouley on January 18, 2007 7:11:42 AM]
TheUnbeliever
TheUnbeliever
I'm not trying to hijack the thread - these questions are closely related to the above.

If you have at least one pure virtual function in the class, then it becomes an abstract class - or does that term's application require there to be no non pure virtual member functions? Related to this, is it a bad thing to toss around objects of type Animal in the above (I can't immediately think of any reason you might want to do this, but maybe there is) - because there is a pure virtual member - or is it just considered really daft to call the pure virtual member?
[TheUnbeliever]
Sc4Freak
Sc4Freak
You can't call the pure virtual function itself - because it has no implementation. That's why you can't instantiate an abstract class and why you can't even attempt to call the pure virtual function.

However, calling the method from a non-abstract derived class is perfectly fine because the derived class MUST provide an implementation or else it, too, is considered an abstract class.
SunTzu
SunTzu
Quote:
Original post by Sc4Freak
You can't call the pure virtual function itself - because it has no implementation. That's why you can't instantiate an abstract class and why you can't even attempt to call the pure virtual function.


Not true. It is entirely possible to both implement and call a pure virtual function. Pure only means that derived classes must override it with an implementation of their own, or else they are not allowed to be instantiated. By your logic, a "pure virtual function" would simply be a virtual function with no implementation, and the =0 syntax would be redundant.

As proof try the following:

class abstractBase{public:    virtual void Func() = 0    {        cout << "In abstract base!" << endl;    }    abstractBase();    virtual ~abstractBase();};class concreteDerived : public abstractBase{public:    void Func()    {        cout << "In concrete derived!" << endl;        abstractBase::Func();    // NOTE call to pure virtual function    }    concreteDerived();    ~concreteDerived();};


Create an object of type concreteDerived, call it's Func(), watch what happens.

Scott Meyers mentions a case where this might be a useful technique in More Effective C++ but I don't have that book with me and can't think of a useful application for it off the top of my head... but it can be done.
TheUnbeliever
TheUnbeliever
Quote:
Original post by SunTzu
Quote:
Original post by Sc4Freak
You can't call the pure virtual function itself - because it has no implementation. That's why you can't instantiate an abstract class and why you can't even attempt to call the pure virtual function.


Not true. It is entirely possible to both implement and call a pure virtual function. Pure only means that derived classes must override it with an implementation of their own, or else they are not allowed to be instantiated. By your logic, a "pure virtual function" would simply be a virtual function with no implementation, and the =0 syntax would be redundant.

As proof try the following:



Create an object of type concreteDerived, call it's Func(), watch what happens.

Scott Meyers mentions a case where this might be a useful technique in More Effective C++ but I don't have that book with me and can't think of a useful application for it off the top of my head... but it can be done.


Thanks, that helped clear it up, mostly. Particularly since I wasn't even entirely certain what I was asking (!) that gave me a better idea of things. ++rating
[TheUnbeliever]
SunTzu
SunTzu
Sorry yeah, I kind of failed to directly answer the original question, instead responding to Sc4Freak, though it seems like you've got the gist... but just to spell it out...

virtual means that derived classes can override this function, and calls to it through a base class pointer will call the derived class function.

virtual ... = 0 means that it is a pure virtual function. That is, an object of this class cannot be instantiated (it is an "abstract" class), and objects of a derived class can be instantiated if and only if they override this function. (Note that subclasses don't have to override it - but if they don't, they also are abstract).

The usual example is that a Shape is an abstract base class while a Triangle (derived from Shape) is a concrete sub class. So Shape would contain at least one pure virtual function, while Triangle would override all of Shape's pure virtual functions, and optionally some of it's non-pure virtual functions as well.

You could then create a Triangle, but couldn't create a Shape, though you might get given a Shape pointer and still be able to use it (through it's virtual functions) even though you don't know whether it's a Triangle or a Square. (Or whatever.)

Then my previous post about whether or not pure virtual functions can be implemented should hopefully make a little more sense.
TheUnbeliever
TheUnbeliever
Perfect. Thanks, that's a concise answer to both questions in there, too. :-)
[TheUnbeliever]
Bregma
Bregma
Quote:
Original post by SunTzu
Scott Meyers mentions a case where this might be a useful technique in More Effective C++ but I don't have that book with me and can't think of a useful application for it off the top of my head... but it can be done.


Here's where you're required to have an pure virual function with an implementation.
  #include <iostream>  // Base is an ABC (abstract base class).  class Base  {  public:    ~Base() = 0;  }  Base::~Base()  {    std::cerr << "Base destructor called.\n";  }  // Derived is a concrete implementation.  class Derived: public Base  {  public:    ~Derived()    {      std::cerr << "Derived destructor called.\n";    }  };  int main()  {    Base* pBase = new Derived();    // use pBase to do something sinful and fattening    delete pBase;  }


Making the destructor of an abstract base class is the idiomatic way to prevent abstrace base class instantiation.

--smw
Stephen M. Webb
Professional Free Software Developer
SunTzu
SunTzu
Quote:
Original post by BregmaHere's where you're required to have an pure virual function with an implementation.




Good point, pure virtual destructors in base classes are the obvious case where there must be an implementation of the pure virtual function. On the other hand they're also an exception to the normal rules in that destructors always get called when the object is destroyed anyway.

Scott Meyers (Effective C++ 3rd Ed) points out that a definition of a pure virtual function is useful as a default. The fact that it's not a separate function helps maintain encapsulation (you can keep it protected as opposed to public), while the fact that it's pure means that the default behaviour has to be explicitly chosen by a derived class (as opposed to a non-pure virtual function which would get used if the derived class simply forgot to implement it's own behaviour).
SunTzu
SunTzu
Sorry, double post.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.