tags:

views:

1399

answers:

7

I'm a little familiar with C++, but the virtual keyword still confuses me. What exactly does it mean? If a function is defined as virtual, is that the same as pure virtual?

+2  A: 

"Virtual" means that the method may be overridden in subclasses, but has an directly-callable implementation in the base class. "Pure virtual" means it is a virtual method with no directly-callable implementation. Such a method must be overridden at least once in the inheritance hierarchy -- if a class has any unimplemented virtual methods, objects of that class cannot be constructed and compilation will fail.

@quark points out that pure-virtual methods can have an implementation, but as pure-virtual methods must be overridden, the default implementation can't be directly called. Here is an example of a pure-virtual method with a default:

#include <cstdio>

class A {
public:
    virtual void Hello() = 0;
};

void A::Hello() {
    printf("A::Hello\n");
}

class B : public A {
public:
    void Hello() {
        printf("B::Hello\n");
        A::Hello();
    }
};

int main() {
    /* Prints:
           B::Hello
           A::Hello
    */
    B b;
    b.Hello();
    return 0;
}


According to comments, whether or not compilation will fail is compiler-specific. In GCC 4.3.3 at least, it won't compile:

class A {
public:
    virtual void Hello() = 0;
};

int main()
{
    A a;
    return 0;
}

Output:

$ g++ -c virt.cpp 
virt.cpp: In function ‘int main()’:
virt.cpp:8: error: cannot declare variable ‘a’ to be of abstract type ‘A’
virt.cpp:1: note:   because the following virtual functions are pure within ‘A’:
virt.cpp:3: note:   virtual void A::Hello()
John Millikin
it must be overridden if you want to instantiate an instance of the class. If you don't create any instances then the code will compile just fine.
Glen
compilation will not fail. If there is no implementation of a (pure) virtual method then that class/object cannot be instantiated. It may not LINK, but it will compile.
Tim
@Glen, @tim: on which compiler? When I try to compile a program which builds an abstract class, it doesn't compile.
John Millikin
@John Compilation will only fail if you try to instantiate an instance of a class that contains a PVF. You can of course instantiate pointer or reference values for such classes.
anon
@Neil: Are you sure? I've tried instantiating as a pointer as well with `A *a = new A`, but that fails with the same error. @Glen: On looking at your comment again, I realize I misread it. Will correct the post.
John Millikin
@John It failed because you created an A instance. A * a = 0; will work. I should perhaps have said "create pointers or references" in my comment.
anon
Also, John, the following isn't quite right: "'Pure virtual' means it is a virtual method with no implementation." Pure virtual methods *can* have implementations. But you can't call them directly: you have to override and use the base class implementation from within the sub-class. This allows you to provide a default part of the implementation. It's not a common technique though.
quark
@quark: Interesting. I'll add that in.
John Millikin
+14  A: 

"A virtual function or virtual method is a function or method whose behavior can be overridden within an inheriting class by a function with the same signature" - wikipedia

"A pure virtual function or pure virtual method is a virtual function that is required to be implemented by a derived class that is not abstract" - Wikipedia

So, the virtual function can be overriden and the pure virtual must be implemented.

Also, a good link for questions like this is http://www.parashift.com/c++-faq-lite/

Diego Dias
So... is pure virtual a keyword, or just a term that is used?
Justin
virtual void Function() = 0; is a pure virtual. The "= 0" indicates is purity.
Goz
Justin, 'pure virtual' is just a term (not a keyword, see my answer below) used to mean "this function cannot be implemented by the base class. As Goz said, adding the "=0" to the end of a virtual function makes it "pure"
Nick Haddad
I believe Stroustrup said that he wanted to add a `pure` keyword, but that Bell Labs was about to make a major release of C++, and his manager wouldn't allow it at that late stage. Adding keywords is a big deal.
quark
+4  A: 

In an C++ class, virtual is the keyword that designates that a method can be overridden (i.e. implemented by) a subclass. For example:

class Shape 
{
  public:
    Shape();
    virtual ~Shape();

    std::string getName() // not overridable
    {
      return m_name;
    }

    void setName( const std::string& name ) // not overridable
    {
      m_name = name;
    }

  protected:
    virtual void initShape() // overridable
    {
      setName("Generic Shape");
    }

  private:
    std::string m_name;
};

In this case a subclass can override the the initShape function to do some specialized work:

class Square : public Shape
{
  public: 
    Square();
    virtual ~Square();

  protected:
    virtual void initShape() // override the Shape::initShape function
    {
      setName("Square");
    }
}

The term pure virtual refers to virtual functions that need to be implemented by a subclass and have not been implemented by the base class. You designate a method as pure virtual by using the virtual keyword and adding a =0 at the end of the method declaration.

So, if you wanted to make Shape::initShape pure virtual you would do the following:

class Shape 
{
 ...
    virtual void initShape() = 0; // pure virtual method
 ... 
};

By adding a pure virtual method to your class you make the class an abstract base class which is very handy for separating interfaces from implementation.

Nick Haddad
Regarding "virtual functions that must be implemented by a subclass" -- that's not strictly true, but the subclass is also abstract if they are not. And abstract classes cannot be instantiated. Also, "cannot be implemented by the base class" seems misleading; I'd suggest that "have not been" would be better since there is no restriction to modifications of the code to add an implementation within the base class.
NVRAM
And "the getName function cannot be implemented by a subclass" isn't quite right. Subclasses can implement the method (w/the same or different signature) but that implementation will not OVERRIDE the method. You could implement Circle as a subclass and implement "std::string Circle::getName()" -- then you could call either method for a Circle instance. But if used through a Shape pointer or reference the compiler would call Shape::getName().
NVRAM
Good points on both fronts. I was trying to stay away from discussing special cases for this example, I'll modify the answer to be more forgiving. Thanks!
Nick Haddad
A: 

Read the answers above for the semantics. I will try to explain the notion of "virtual" and "pure virtual" in English so you can remember:

  • "Virtual" means it is there "virtually." Like virtual reality, you can sort of touch and feel it but you can also easily manipulate it.
  • "Pure Virtual" is just pure fiction! It's not there at all (as indicated by assignment to zero). It's doesn't exist.

Hope this helps.

kvs
+4  A: 

The virtual keyword gives C++ its' ability to support polymorphism. When you have a pointer to an object of some class such as:

class Animal
{
  public:
    virtual int GetNumberOfLegs() = 0;
};

class Duck : public Animal
{
  public:
     int GetNumberOfLegs() { return 2; }
};

class Horse : public Animal
{
  public:
     int GetNumberOfLegs() { return 4; }
};

void SomeFunction(Animal * pAnimal)
{
  cout << pAnimal->GetNumberOfLegs();
}

In this (silly) example, the GetNumberOfLegs() function returns the appropriate number based on the class of the object that it is called for.

Now, consider the function 'SomeFunction'. It doesn't care what type of animal object is passed to it, as long as it is derived from CAnimal. The compiler will automagically cast any CAnimal-derived class to a CAnimal as it is a base class.

If we do this:

Duck d;
SomeFunction(&d);

it'd output '2'. If we do this:

Horse h;
SomeFunction(&h);

it'd output '4'. We can't do this:

Animal a;
SomeFunction(&a);

because it won't compile due to the GetNumberOfLegs() virtual function being pure, which means it must be implemented by deriving classes (subclasses).

Pure Virtual Functions are mostly used to define:

a) abstract classes

These are base classes where you have to derive from them and then implement the pure virtual functions.

b) interfaces

These are 'empty' classes where all functions are pure virtual and hence you have to derive and then implement all of the functions.

JBRWilkinson
+2  A: 

I'd like to comment on Wikipedia's definition of virtual, as repeated by several here. Wikipedia defines a virtual method as one that can be overridden in subclasses. That is incorrect: any method, not just virtual ones, can be overridden in subclasses. What virtual does is to give you polymorphism, that is, the ability to select at run-time the most-derived override of a method.

Consider the following code:

#include <iostream>
using namespace std;

class Base {
public:
    void NonVirtual() {
        cout << "Base NonVirtual called.\n";
    }
    virtual void Virtual() {
        cout << "Base Virtual called.\n";
    }
};
class Derived : public Base {
public:
    void NonVirtual() {
        cout << "Derived NonVirtual called.\n";
    }
    void Virtual() {
        cout << "Derived Virtual called.\n";
    }
};

int main() {
    Base* bBase = new Base();
    Base* bDerived = new Derived();

    bBase->NonVirtual();
    bBase->Virtual();
    bDerived->NonVirtual();
    bDerived->Virtual();
}

What is the output of this program?

Base NonVirtual called.
Base Virtual called.
Base NonVirtual called.
Derived Virtual called.

Derived overrides every method of Base: not just the virtual one, but also the non-virtual.

We see that when you have a Base-pointer-to-Derived (bDerived), calling NonVirtual calls the Base class implementation. This is resolved at compile-time: the compiler sees that bDerived is a Base*, that NonVirtual is not virtual, so it does the resolution on class Base.

However, calling Virtual calls the Derived class implementation. Because of the keyword virtual, the selection of the method happens at run-time, not compile-time. What happens here at compile-time is that the compiler sees that this is a Base*, and that it's calling a virtual method, so it insert a call to the vtable instead of class Base. This vtable is instantiated at run-time, hence the run-time resolution to the most-derived override.

I hope this wasn't too confusing. In short, any method can be overridden, but only virtual methods give you polymorphism, that is, run-time selection of the most derived override. In practice, however, overriding a non-virtual method is considered bad practice and rarely used, so many people (including whoever wrote that Wikipedia article) think that only virtual methods can be overridden.

Dr_Asik
Just because the Wikipedia article (which I am no way defending) defines a virtual method "as one that can be overridden in subclasses" doesn't exclude the possibility that other, non-virtual, methods with the same name can be declared. This is known as overloading.
anon
The definition is nonetheless incorrect. A method that can be overridden in a derived class is not virtual by definition; whether the method can be overridden is irrelevant to the definition of "virtual". Also, "overloading" usually refers to having multiple methods with the same name and return type but different arguments, in the same class; it is very different from "overriding" which implies exactly the same signature but in a derived class. When it is done non-polymorphically (non-virtual base), it is often called "hiding".
Dr_Asik
A: 

Simula, C++, and C#, which use static method binding by default, the programmer can specify that particular methods should use dynamic binding by labeling them as virtual. Dynamic method binding is central to object-oriented programming.

Object oriented programming requires three fundamental concepts: encapsulation, inheritance, and dynamic method binding.

Encapsulation allows the implementation details of an abstraction to be hidden behind a simple interface.

Inheritance allows a new abstraction to be defined as an extension or refinement of some existing abstraction, obtaining some or all of its characteristics automatically.

Dynamic method binding allows the new abstraction to display its new behavior even when used in a context that expects the old abstraction.

tuckster