Declaration and Definition of Virtual Member Functions in C++

Polymorphism is one of the most important feature of OOP. C++ implements polymorphism by the combination of virtual member functions and pointers (references). As a C++ user, of course you know how to use virtual member function and pointers (references) to achive polymorphism. But there might be a fuzzy zone left around these concepts. For example, have you ever think about the following question?

Can a pure virtual function has a implementation?

This post discuss declaration and definition of virtual member functions in C++.

Short Answer to the Question

Yes, we could give a definition of a pure virtual function, and sometimes we must give such a definition. But remember, unlike other member functions, the definition of a pure virtual member function should be implemented outside the definition of the class contains it. (see the example below)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct Abstract {
virtual void f() = 0; // pure virtual
~Abstract() {
// f(); // undefined behavior
Abstract::f(); // OK: non-virtual call
}
};

// definition of the pure virtual function
void Abstract::f() { std::cout << "A::f()\n"; }

struct Concrete : Abstract {
void f() override {
Abstract::f(); // OK: calls pure virtual function
}
~Concrete() {
f(); // OK: calls Concrete::f()
}
};

Virtual Member Functions

Here, we begin to discuss the rules about declaration and definition of virtual member functions. According to the C++ standard, a virtual member function declared in the definition of a class must have a definition (implementation). Remember that, when you are trying to give implementation of a virtual member function, you cannot mark virtual again outside the class definition.

1
2
3
4
5
6
7
8
9
10
11
12
13
struct Foo {
virtual void foo() { // declare and define at the same time, inside the class definition.
std::cout << "Foo::foo()" << std::endl;
}
};

struct Bar {
virtual void bar();
};

void Bar::bar() {
std::cout << "Bar::bar()" << std::endl;
}

However, this rule is not required to give a diagnose when compiling. That is to say, if the definition of a virtual member function is missing, your compiler may not report an error. However, your linker might report it for referancing undefined symbol.

Pure Virtual Member Functions

Pure virtual functions mark classes who contain them as “abstract class”. It means that no objects of an abstract calss could be created, and we cannot use it as parameter types, as function return types, or as the type of an explicit conversion.

As a result, we’ll never have a chance to call virtual member functions declared in an abstract class from its object. On the other hand, since it’s a pure virtual function and will defintely be overrided in dirved classes. In consquence, in most cases, impl of pure virtual function is useless. Therefore, we can declare a function as pure function and give no definition of it.

That is to say, for pure virtual member function, we could:

  • declare it in class definition, and give no implementation of it;
  • declare it in class definition, and do give implementation of it outside the class definition.

But remember, there are two exceptions.

  1. for pure virtual destructor, you’ll have to provide a definition.
  2. the member functions of the derived class are free to call the abstract base’s pure virtual function using qualified function id (Base::some_pure_virtual_function()).

In these two cases, definition of pure virtual function makes sense.

If this post helps you, please consider to buy a cup of coffee for me.