Under What Circumstances Is It Advantageous to Give an Implementation of a Pure Virtual Function

Under what circumstances is it advantageous to give an implementation of a pure virtual function?

Declared destructors must always be implemented as the implementation will call them as part of derived object destruction.

Other pure virtual functions may be implemented if they provide a useful common functionality but always need to be specialized. In the case, typically derived class implementations will make an explicit call to the base implementation:

void Derived::f()
{
Base::f();

// Other Derived specific functionality
}

Typically, you make a destructor virtual if you need to make a class abstract (i.e. prevent non-derived instances from being created) but the class has no other functions that are naturally pure virtual. I think the 'trust me it's faster' is refering to the fact that because destructors called as part of derived object clean up don't need to use a vtable lookup mechanism, the inline implementation can be taken advantage of, unlike typical virtual function calls.

Pure virtual function with implementation

A pure virtual function must be implemented in a derived type that will be directly instantiated, however the base type can still define an implementation. A derived class can explicitly call the base class implementation (if access permissions allow it) by using a fully-scoped name (by calling A::f() in your example - if A::f() were public or protected). Something like:

class B : public A {

virtual void f() {
// class B doesn't have anything special to do for f()
// so we'll call A's

// note that A's declaration of f() would have to be public
// or protected to avoid a compile time problem

A::f();
}

};

The use case I can think of off the top of my head is when there's a more-or-less reasonable default behavior, but the class designer wants that sort-of-default behavior be invoked only explicitly. It can also be the case what you want derived classes to always perform their own work but also be able to call a common set of functionality.

Note that even though it's permitted by the language, it's not something that I see commonly used (and the fact that it can be done seems to surprise most C++ programmers, even experienced ones).

Does it make any sense to define pure virtual functions in the base class itself?

are there any situations when it is beneficial to define a pure virtual function in the base class itself?

Yes - if the function in question is the pure virtual destructor, it must also be defined by the base class.

Why does C++ support pure virtual functions with an implementation?

C++ Supports pure virtual functions with an implementation so class designers can force derived classes to override the function to add specific details , but still provide a useful default implementation that they can use as a common base.

Classic example:

class PersonBase
{
private:
string name;
public:
PersonBase(string nameIn) : name(nameIn) {}

virtual void printDetails() = 0
{
std::cout << "Person name " << name << endl;
}
};

class Student : public PersonBase
{
private:
int studentId;
public:
Student(string nameIn, int idIn) : PersonBase(nameIn), studentId(idIn) { }
virtual void printDetails()
{
PersonBase::printDetails(); // call base class function to prevent duplication
std::cout << "StudentID " << studentId << endl;
}
};

What is the point of a pure-virtual member function with function body?

What are sensible use cases for this?

If the function has a sensible default implementation, or a partial implementation of whatever is relevant to the base class, but you still want to force derived classes to override it, that's a good place to put it.

Also, as noted in the comments, you might want to force a class with no pure virtual functions to be abstract. You can do this by making the destructor pure virtual; but the destructor must have a body, whether or not it's pure virtual.

when would A::foo ever be called?

It can only be called non-virtually; for example:

struct B : A {
void f(int i) const {
A::foo(i); // non-virtual call
// Do the B-specific stuff
}
};

why is this the correct/best implementation?

The alternative would be to invent a new name for the partial/default implementation, in addition to an unimplemented pure virtual function.

Are there any differences here between C++03 and C++11?

No.

Is it dangerous to create pure virtual function of a virtual function?

From ISO IEC 14882 2014:

§ 10.4 says:

5 [ Note: An abstract class can be derived from a class that is not abstract, and a pure virtual function may
override a virtual function which is not pure. —end note ]

So It's perfectly possible to do that.

Example of use case:

You can have a basic type, that is implemented as a concrete type (base class). Now, for subtypes, we might be in a need of further additional information. So, we can have an abstract intermediate object to meet our needs.

What are the uses of pure virtual functions in C++?

Briefly, it's to make the class abstract, so that it can't be instantiated, but a child class can override the pure virtual methods to form a concrete class. This is a good way to define an interface in C++.

Why use virtual functions?

You use virtual functions when you want to override a certain behavior (read method) for your derived class rather than the one implemented for the base class and you want to do so at run-time through a pointer to the base class.

The classic example is when you have a base class called Shape and concrete shapes (classes) that derive from it. Each concrete class overrides (implements a virtual method) called Draw().

The class hierarchy is as follows:

Class hierarchy

The following snippet shows the usage of the example; it creates an array of Shape class pointers wherein each points to a distinct derived class object. At run-time, invoking the Draw() method results in the calling of the method overridden by that derived class and the particular Shape is drawn (or rendered).

Shape *basep[] = { &line_obj, &tri_obj,
&rect_obj, &cir_obj};
for (i = 0; i < NO_PICTURES; i++)
basep[i] -> Draw ();

The above program just uses the pointer to the base class to store addresses of the derived class objects. This provides a loose coupling because the program does not have to change drastically if a new concrete derived class of shape is added anytime. The reason is that there are minimal code segments that actually use (depend) on the concrete Shape type.

The above is a good example of the Open Closed Principle of the famous SOLID design principles.

Why do we need a pure virtual destructor in C++?

  1. Probably the real reason that pure virtual destructors are allowed is that to prohibit them would mean adding another rule to the language and there's no need for this rule since no ill-effects can come from allowing a pure virtual destructor.

  2. Nope, plain old virtual is enough.

If you create an object with default implementations for its virtual methods and want to make it abstract without forcing anyone to override any specific method, you can make the destructor pure virtual. I don't see much point in it but it's possible.

Note that since the compiler will generate an implicit destructor for derived classes, if the class's author does not do so, any derived classes will not be abstract. Therefore having the pure virtual destructor in the base class will not make any difference for the derived classes. It will only make the base class abstract (thanks for @kappa's comment).

One may also assume that every deriving class would probably need to have specific clean-up code and use the pure virtual destructor as a reminder to write one but this seems contrived (and unenforced).

Note: The destructor is the only method that even if it is pure virtual has to have an implementation in order to instantiate derived classes (yes pure virtual functions can have implementations, being pure virtual means derived classes must override this method, this is orthogonal to having an implementation).

struct foo {
virtual void bar() = 0;
};

void foo::bar() { /* default implementation */ }

class foof : public foo {
void bar() { foo::bar(); } // have to explicitly call default implementation.
};


Related Topics



Leave a reply



Submit