answersLogoWhite

0

In C++, a pure virtual function is a function declaration that has no implementation in the class where it is declared, but is rather left to the child classes to override and define the function. This means that the parent class cannot be instantiated. In Java this is known as an abstract class or interface.

User Avatar

Wiki User

17y ago

Still curious? Ask our experts.

Chat with our AI personalities

LaoLao
The path is yours to walk; I am only here to hold up a mirror.
Chat with Lao
MaxineMaxine
I respect you enough to keep it real.
Chat with Maxine
SteveSteve
Knowledge is a journey, you know? We'll get there.
Chat with Steve
More answers

We use virtual functions whenever we create a class which we expect to be used as a base class. Virtual functions are simply functions that we expect to be overridden by those classes. Whenever we implicitly invoke a virtual method, the most-derived override of that method is automatically invoked, even if we do not know the specific type of that derivative.

Let us consider the following minimal example in C++ which requires some means of differentiating between different types of the same class. For this we will use a type field:

#include

#include

enum g_type {a, b, c};

class bad {

g_type m_type;

public:

bad (g_type type): m_type (type) {}

std::string type() const;

};

std::string bad::type () const {

switch (m_type)

{

case a: return "A";

case b: return "B";

case c: return "C";

}

}

void print_type (const bad& object) { std::cout << object.type() << std::endl;

}

int main () {

bad x (a);

bad y (b);

bad z (c);

print_type (x);

print_type (y);

print_type (z);

}

Output:

A

B

C

This class isn't particularly useful but it is capable of determining it's own type from the type field, which is the only part the really interests us. Other methods that depend upon that type field can obviously make use of a similar switch/case structure to the one found in the bad::type() method, and thus provide implementations that are specific to each of those types. However, this is bad design for several reasons:

  1. If we wish to add a new type to the class, such as a type d or a type e, we would have to modify the global enum (g_type) and we would have to modify every single method that was dependent upon the class type field. While that is not an impossible task at this stage, imagine if we had 100 methods and 100 types to cater for. Suddenly it becomes a lot of work just to add one new type.
  2. If we pass objects of this class to external functions, and those functions are reliant upon the type field, they, too, must include a switch/case structure to determine how to operate upon the object, and those methods also have to be updated whenever new types are created.
  3. Imagine we have a program that makes use of this class, but only makes use of some of the available types but not others. Our class would then contain a lot of "specialised" code that would never actually be required by our program. That's a waste of memory.
  4. How can end-users add new types of their own? If we assume we wish to distribute this class to other programmers through a class library, they won't have access to the source code and therefore cannot cater for new types. Even if we do provide the source code, they won't thank you for implementing the class in this way, mostly because they are not remotely interested in the implementations you've provided, they are only interested in adding their own implementations, and you've made it doubly difficult for them to locate all the areas of your code that need to be modified.

All these problems can be address through virtual functions. Consider the following alternative:

#include

#include

class good {

public:

virtual std::string type() const {return "base class";}

};

class a : public good {

public:

virtual std::string type () const override {return "A";}

};

class b : public good {

public:

virtual std::string type () const override {return "B";}

};

class c : public good {

public:

virtual std::string type () const override {return "C";}

};

void print_type (const good& object) {

std::cout << object.type() << std::endl;

}

int main () {

a x;

b y;

c z;

print_type (x);

print_type (y);

print_type (z);

}

Output:

A

B

C

[It should be noted that C++ methods are non-virtual by default while Java methods are virtual by default. While it could be argued that it makes more sense for all methods to be virtual by default, C++ inherits from C and since there are no virtual methods in C, they are non-virtual by default in order to maintain compatibility with C.]

Obviously this example has more classes, but that is entirely the point. Each class (a, b and c) "knows" its own type, so the base class doesn't have to specifically cater for them. The classes a, b and c are simply more specialised versions of their base class, and each caters only for its own type. You will note that although the print_type function expects a "good" object and invokes its type() function, the output is not "base class" as you might expect. Derived objects behave according to their most-derived type, so when you invoke a virtual method, the most-derived override is invoked automatically. This is known as polymorphism, where derived object's behave according to their actual type. This works even when the function knows nothing about the derivatives. However, it only works when we pass objects by reference (or by pointer). If we pass a derived object and the function expects a base class by value rather than by reference, the base class will be copied without the derived portion of the object. This is known as "object slicing" and is usually undesirable.

The implementation greatly reduces the cost of maintenance because if we need a new type we simply derive a new class and that new class caters specifically for that new type and nothing else. We do not have to modify the base class, nor do we have to modify any other classes, we simply override the virtual methods provided by the base class. End-users can also create their own types much more easily, even if they have no access to the source code. All they need to know can be found in the declaration of the "good" base class (which can be found in the class header which must be distributed with the class library). Classes a, b and c can actually be defined in completely separate files (or libraries) in order to maintain modularity.

Moreover, our programs no longer need to include code that will never be invoked, only the classes we physically instantiate need to be compiled, even if we include classes we never actually use. All the code that pertains to a specific class is encapsulated by that class. The "good" class essentially provides the interface to all its derivatives, even if the code that operates upon "good" classes doesn't know anything about those derivatives. And that's just as it should be because when you ship a base class you have no way of knowing what derivatives other programmers may derive from your base class.

Note that all base classes must have a virtual destructor. This is how you determine if a class can be used as a base class or not. If it does not have a virtual destructor and does not inherit from any other classes then it is not intended to be used as a base class. However, if it has one or more virtual methods, it must also have a virtual destructor.

The reason we need a virtual destructor is because derived objects must be destroyed in the reverse order they were constructed. Construction always begins from the least-derived class because a derived object cannot exist until its base class has been fully constructed. But during destruction, the derived class must be destroyed before its base class can be destroyed. If it weren't (if the destructor were not virtual), code that isn't aware of the derived class may destroy the base class, leaving an incomplete object in memory. We can see this working in the following minimal example:

#include

class base {

public:

base () {std::cout<<"creating base"<

~base () {std::cout<<"destroying base"<

};

class derived : public base {

public:

derived () {std::cout<<"creating derived"<

~derived () {std::cout<<"destroying derived"<

};

int main () {

base* object = new derived;

delete object;

object = nullptr;

}

Output:

creating base

creating derived

destroying base

As you can see, we constructed a derived object but we didn't destroy it. It's still in memory, but it's no longer valid because its base class no longer exists. Note that the "object" variable is a pointer to the base class of the derived class. This is valid because a derived class is said to be a "kind of" base and is really no different to our print_type function in the previous example which accepted a reference to a "good" object, even though we actually passed references to a, b and c objects.

To fix this, we need a virtual destructor:

class base { public:

base () {std::cout<<"creating base"<

virtual ~base () {std::cout<<"destroying base"<

};

Now we get the expected behaviour and the objects are both created and destroyed in the correct order:

creating base

creating derived

destroying derived

destroying base

User Avatar

Wiki User

9y ago
User Avatar

You declare a pure virtual function whenever you wish your class to be an abstract data type and require all derivatives of the class to provide an implementation for the pure virtual function. Unlike a non-pure virtual function which needn't be overridden by derivatives, pure virtual functions must be overridden. Once a derivative provides an implementation, that function becomes non-pure virtual, and can then be inherited by derivatives of that derivative.

User Avatar

Wiki User

11y ago
User Avatar

You declare a pure-virtual method in base classes that are intended to provide a common interface to two or more derived classes. Any class that declares a method as pure-virtual becomes an abstract base class (ABC), also known as an abstract data type (ADT).

You cannot instantiate abstract classes, but that's fine because the intent is to derive classes from the abstract class and define specialised implementations for the pure-virtual methods in each of the derived classes. The base class exists purely to provide a common interface to all its derivatives.

User Avatar

Wiki User

12y ago
User Avatar

Virtual functions must be implemented in the base class, but they need not be implemented in their derived classes. Derived classes will automatically inherit the base class implementations of all virtual functions, but can override those functions by providing their own implementations. The base class methods can still be called explicitly to provide common functionality. A function that is declared virtual is expected to be implemented by derived classes, but it is not a requirement.

Pure-virtual functions need not be implemented in the base class, but they must be implemented in the derived classes. Any class that declares a pure-virtual function is automatically rendered an ADT (abstract data type) and cannot be instantiated other than through derivation. Derived classes do not inherit any of the abstract base class implementations, but they can call them explicitly. Derived classes that do not implement all the pure-virtual functions inherited from their abstract base classes are automatically rendered abstract themselves, however any implementations they do provide are subsequently treated as virtual methods (and are therefore inherited by derivatives). A concrete class is a class that inherits or implements the sum total of all pure-virtual methods inherited from all abstract base classes. Only concrete classes can be instantiated without being derived from.

[Edit: original answer was incomplete and misleading.]

User Avatar

Wiki User

12y ago
User Avatar

Virtual functions are expected to be overridden by derived classes. Pure-virtual functions must be overridden by derived classes.

User Avatar

Wiki User

11y ago
User Avatar

A pure virtual function can not be instanced directly, only in a derived class. A normal virtual function has no such requirement.

User Avatar

Wiki User

12y ago
User Avatar

so it can call it polymorphic-ally.

User Avatar

Wiki User

15y ago
User Avatar

Add your answer:

Earn +20 pts
Q: What is pure virtual functions?
Write your answer...
Submit
Still have questions?
magnify glass
imp
Continue Learning about Engineering

How do you represent a C plus plus non-pure virtual function in UML?

All virtual functions (including pure-virtual functions) are represented in italics. All non-virtual functions are represented normally. There is no differentiation between pure and non-pure virtual functions, however some people append "=0" to distinguish the pure-virtual functions.


What is the difference between virtual function and function overriding?

Virtual Functions and Pure Virtual Functions are relevant in the context of class inheritance.Unlike Virtual Functions, Pure Virtual Functions do not require a body. This implies that when a base class defining such a function is inherited, the derived class must implement that function. Furthermore, the base class becomes abstract; meaning you cannot create an instance of the base class even if a body is implemented for the function. You are expected to derive from abstract classes; only the derived classes that implement all the inherited Pure Virtual functions can be instantiated.Here are some examples of Virtual and Pure Virtual function signatures:- Virtual Function: E.g. virtual void myFunction();- Pure Virtual Function: E.g. virtual void myFunction() = 0;


Can you have inline virtual functions in a class?

No, inlining is done at compile time whereas virtual functions are resolved at run time(late binding). So, virtual functions can't be inlined. Both properties are orthogonal.Inlining is a mere suggestion the compiler may ignore it if it is declared with virtual function.


A pure virtual function is a virtual function that has?

A pure-virtual function is a function that must be overridden in derived classes. You simply add "=0" to the end of the function declaration. class AbstractClass { public: virtual void DoSomething()=0; // Pure-virtual. };


When do we make a virtual function pure?

We make a virtual function pure whenever we wish to make our class an abstract base class (an abstract data type). Unlike a virtual function, pure virtual functions must be overridden by a derived class or by one of its derivatives (the function remains pure virtual until it is overridden, at which point it becomes virtual). Derived classes that do not provide a complete implementation for all the pure virtual functions it inherits become abstract themselves. You cannot instantiate an abstract base class other than through derivation.