Inherited pure virtual functions - c++

Let's imagine the following situation: A is an abstract class defining a pure virtual function void f(); B is a class that implements a function void f(); C inherits from both A and B:
struct A
{
void virtual f() =0;
};
struct B
{
virtual void f() { }
};
struct C : public A, public B
{
};
The question could be: Is C an abstract class? The requirements deriving from A being abstract are that the subclass implements the virtual function void f(). C does not implement it directly, but inherits it from B.
I can already answer this question: Yes, C is an abstract class. If you try to instantiate an object of type C you'll get a compilation error. So the actual question is: Why is C an abstract class?
I suppose that the fact that A::f and B::f have the same name and signature is not enough to draw a correspondence between these functions so to say that B::f implements A::f. From a technical point of view I can see that these functions "reside" in different parts of the object of type C (though I'm not really sure that my understanding is complete). But from a conceptual point of view I could easily imagine a situation where a class C wants to be an implementation of the abstract class A and, in order to implement the pure virtual function f, it uses the implementation of one of its parent classes. The solution is probably to do:
struct C : public A, public B
{
virtual void f() { B::f(); }
};
, which worked in my experiment. But is this trick necessary?
EDIT:
Further question: Is the order in which C inherits from A and B relevant? Would it change something if I wrote the following?
struct C : public B, public A
{
};
The answer (again, I test my codes, then I try to ask non-trivial questions) is no, it does not change anything. But in this case (correct me if I'm wrong), C::f, if implemented, would override B::f, not A::f. Since A::f would not be accessible using a C object does it make sense to request that it is implemented?

C also inherits from B doesn't make a bit of difference when it considers the functions inherited from A. So, when it compiler sees that C doesn't override pure virtual from A, it makes it an abstract class.

The requirements deriving from A being abstract are that the subclass implements the virtual function
Not quite. The requirement is that the subclass overrides the pure virtual function, with a non-pure function. A function in one base class doesn't override one in another base class; C itself must declare an override to be non-abstract.
But is this trick necessary?
Yes. You have to override the function in a class derived from A; in this case, that means C.
Is the order in which C inherits from A and B relevant?
No, the declaration order makes little difference. The override must be declared in a class derived from A.
But in this case (correct me if I'm wrong), C::f, if implemented, would override B::f, not A::f.
It would override both, regardless of the declaration order of the base classes.
Since A::f would not be accessible using a C object does it make sense to request that it is implemented?
Both are still accessible (although the name will need to be qualified since an unqualified f is ambiguous). The pure function still needs to be overridden to make the derived class non-abstract.

Since the other answers haven't been updated for your new questions, here are the answers to them.
But in this case (correct me if I'm wrong), C::f, if implemented, would override B::f, not A::f.
You're half wrong. Both A::f and B::f are overridden by C::f regardless of the order of inheritance.
Since A::f would not be accessible using a C object does it make sense to request that it is implemented?
But A::f is accessible using a C object. Consider this, rather typical use of inheritance:
void call_f(A& a) {
a.f();
}
int main() {
C c;
call_f(c);
}
If C doesn't override A::f, then this couldn't possibly work. It makes sense that a concrete subclass of A must implement A::f.

Related

Can a C++ class without any pure virtual methods be considered abstract?

My understanding is that abstract classes must have one or more pure virtual methods.
Can this class be considered abstract?
class B {
protected:
B() { }
public:
virtual ~B() { }
};
Finally, is the term abstract class defined in any of the recent C++ standards?
No, such a class cannot be considered abstract because (as mentioned in the comments, excerpt from the working draft):
A class is abstract if it has at least one pure virtual function.
Unfortunately, there are cases when one cannot add a pure virtual method to a class to turn it in an abstract one and still he doesn't want users to be able to instantiate that class.
For the sake of curiosity, I'm adding this answer to mention an often unknown technique to work around the issue.
Actually, you can easily turn such a class in an abstract one, even if you don't have any virtual method to be added to it.
The basic idea is to exploit the destructor declaration to do that.
A minimal, (not) working example follows:
struct B { virtual ~B() = 0; };
// keep in mind the ODR
B::~B() { }
int main() { B b{}; }
The code above won't compile with the error:
cannot declare variable 'b' to be of abstract type 'B'
Please, note that the definition of the destructor should be placed in a .cpp file, so as not to violate the ODR.
To be honest, I haven't found any case in which this technique can be used till now. Anyway, it's worth mentioning it for future readers.
abstract classes must have one or more pure virtual methods.
Exactly, and you class don't have it.
In accordance with this, a abstract class is a type which cannot be instantiated, but can be used as a base class (note: not "by"). In C++ this can be achieved with the usage of pure virtual method.
A pure virtual method is a virtual function whose declarator has the following syntax:
class B {
virtual void foo() = 0;
}
Note: the syntax = 0 which indicates a pure virtual method. That simply means you don't have to specify an implementation for that method, and it cannot be possible to create any instance of that class (that is, a abstract class).
In conclusion your class B is not an abstract class.
Finally, is the term abstract class defined in any of the recent C++ standards?
The abstract class is a definition itself, and it's define as I've just mentioned before.
If you mean a specific defined syntax as, for example in Java (abstract class ...), then the answer is no. Again an abstract class in C++ is defined just with a class which has a pure virtual method.
No, class B can not be considered as abstract.
class A {
public:
virtual void method() = 0;
virtual ~A() = 0;
}
A is pure virtual, you cannot create object of A. You must create children class B which implements method after A.

what's the necessity of the implementation of a pure virtual function

Pure virtual functions are a must-have property for abstract base classes. So no implementations should be made, which is very intuitive to understand. But Recently I came to know that pure virtual functions can still be defined later and be invoked statically(not by object instances). I can't think up a reason for this. If one virtual function is defined as pure, then what's the reason to implement it?
class A{
public:
...
virtual void interface() = 0; //Pure Virtual functions
...
}
void A::interface() //Implementation
{
cout<<"This the implementation for A interface";
}
I am curious about the logic behind this. Why is c++ designed like this way?
It might make sense to have a "default" implementation, which concrete classes can use if it's useful to them. They still need to override it, but can call the base-class version non-virtually:
struct B : A {
void interface() {
A::interface(); // call the default implementation
// and maybe do some B-specific things too
}
};
I can't think up a reason for this. If one virtual function is defined as pure, then what's the reason to implement it?
The purpose of a pure virtual function is not to prohibit definitions. It is to mark the class as uninstantiable.
Providing a definition may be useful for deriving classes:
struct A
{
virtual void foo() = 0;
};
void A::foo()
{
/* some common logic here */
}
struct B : A
{
virtual void foo() overrides
{
bar();
A::foo();
}
void bar();
};
struct C : A
{
virtual void foo() overrides
{
baz();
A::foo();
}
void baz();
};
A pure virtual function simply means that the function must be overidden by all derived classes it does not mean that the function cannot/should not have a implementation of its own. Two most obvious cases for such a pure virtual function having implementation are:
A Derived class implementation can call Base class implementation
Sometimes you would want a base class to be made abstract but there is no method which you can mark as pure virtual in such a case a destructor is most obvious choice but in such a destructor still needs a implementation.
interface() = 0 means derived classes must provide an implementation, so the definition effects derived classes, but the base class is permitted to have an implementation of the method so that derived classes can always call base::interface().
You apparently completely misunderstood the meaning of the term "statically" in this context.
Yes, pure virtual functions can still have bodies, i.e. they can still be defined.
And no, you cannot invoke such function "without an object instance", as you seem to incorrectly believe. A pure virtual function with a body is still a non-static member function. It still requires an object instance to be invoked.
When someone says that such function can be invoked "statically", it means that it can be called directly, without using virtual dispatch mechanism. Function calls that go through virtual dispatch are sometimes called "virtual calls" or "dynamic calls", while direct function calls are sometimes called "static calls". The term "static" in this context assumes a completely different meaning, not connected in any way to static member functions.
In C++ language a direct non-virtual (i.e. "static") call can be performed explicitly by specifying a qualified member name in the call. For example, if class B derives from your class A, then inside some method B::foo() you can use the following syntax
void B::foo() {
A::interface(); // <- qualified method name
}
which performs a direct call to the implementation of A::interface() you provided. For an object b of type B the same kind of call can be performed as
B b;
b.A::interface(); // <- qualified method name
In both cases the call is performed for a specific object (*this in the first example, and b in the second).
Pretty much the same thing happens implicitly when destructors of derived classes call destructors of base class, which is why you will often encounter this situation with pure virtual destructors (i.e. they are declared as pure virtual, yet have a body).

Virtual unnecessary for protected functions

Say class B derives from class A. That both declare f(). f is protected. Hence f will only be called inside A and inside B. Does f() need to be declared virtual?
Or rather: say C derives from B derives from A. B and A declare protected non-virtual f(). Will a call to f() in C and B resolve to B::f() and in A to A::f()?
In that case, should we always avoid virtual for protected members to have static resolution? Is this done automatically? Thanks!
As long as the call to f() is done in a function derived from A (and not overloaded/reimplemented in B or C), the this pointer resolves to A* and therefore A::f() is called. So no, you still need a virtual function in this case.
Declaring your protected method virtual is necessary when you want polymorphic behaviour (an example to this is the Template Method pattern), and is to be avoided when you don't. However, in the latter case you should not shadow the function with another function having the same signature in the subclass, otherwise you get puzzling behaviour (like the one you describe in your 2nd paragraph) which opens up the possibility for subtle bugs.
I am a bit rusty on my C++ but I would say that "static resolution" would only be guaranteed when you declare the method private and thus you need virtual together with protected in your scenario...
So:
class A {
public:
void f() { std::cout << "A::f\n"; }
};
class B : public A {
public:
void f() { std::cout << "B::f\n"; }
};
As long as the compiler knows that an object is actually a B, it will call f() in B. But, this is not always the case:
void callF(A* a)
{
a->f();
}
B b;
callF(&b); // prints A::f
If you want functions like callF to call the correct f() function, make it virtual. Generally, you make functions virtual if it makes sense to override them in a descendant class. This is often the case for protected functions.

C++ "virtual" keyword for functions in derived classes. Is it necessary?

With the struct definition given below...
struct A {
virtual void hello() = 0;
};
Approach #1:
struct B : public A {
virtual void hello() { ... }
};
Approach #2:
struct B : public A {
void hello() { ... }
};
Is there any difference between these two ways to override the hello function?
They are exactly the same. There is no difference between them other than that the first approach requires more typing and is potentially clearer.
The 'virtualness' of a function is propagated implicitly, however at least one compiler I use will generate a warning if the virtual keyword is not used explicitly, so you may want to use it if only to keep the compiler quiet.
From a purely stylistic point-of-view, including the virtual keyword clearly 'advertises' the fact to the user that the function is virtual. This will be important to anyone further sub-classing B without having to check A's definition. For deep class hierarchies, this becomes especially important.
The virtual keyword is not necessary in the derived class. Here's the supporting documentation, from the C++ Draft Standard (N3337) (emphasis mine):
10.3 Virtual functions
2 If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf.
No, the virtual keyword on derived classes' virtual function overrides is not required. But it is worth mentioning a related pitfall: a failure to override a virtual function.
The failure to override occurs if you intend to override a virtual function in a derived class, but make an error in the signature so that it declares a new and different virtual function. This function may be an overload of the base class function, or it might differ in name. Whether or not you use the virtual keyword in the derived class function declaration, the compiler would not be able to tell that you intended to override a function from a base class.
This pitfall is, however, thankfully addressed by the C++11 explicit override language feature, which allows the source code to clearly specify that a member function is intended to override a base class function:
struct Base {
virtual void some_func(float);
};
struct Derived : Base {
virtual void some_func(int) override; // ill-formed - doesn't override a base class method
};
The compiler will issue a compile-time error and the programming error will be immediately obvious (perhaps the function in Derived should have taken a float as the argument).
Refer to WP:C++11.
Adding the "virtual" keyword is good practice as it improves readability , but it is not necessary. Functions declared virtual in the base class, and having the same signature in the derived classes are considered "virtual" by default.
There is no difference for the compiler, when you write the virtual in the derived class or omit it.
But you need to look at the base class to get this information. Therfore I would recommend to add the virtual keyword also in the derived class, if you want to show to the human that this function is virtual.
The virtual keyword should be added to functions of a base class to make them overridable. In your example, struct A is the base class. virtual means nothing for using those functions in a derived class. However, it you want your derived class to also be a base class itself, and you want that function to be overridable, then you would have to put the virtual there.
struct B : public A {
virtual void hello() { ... }
};
struct C : public B {
void hello() { ... }
};
Here C inherits from B, so B is not the base class (it is also a derived class), and C is the derived class.
The inheritance diagram looks like this:
A
^
|
B
^
|
C
So you should put the virtual in front of functions inside of potential base classes which may have children. virtual allows your children to override your functions. There is nothing wrong with putting the virtual in front of functions inside of the derived classes, but it is not required. It is recommended though, because if someone would want to inherit from your derived class, they would not be pleased that the method overriding doesn't work as expected.
So put virtual in front of functions in all classes involved in inheritance, unless you know for sure that the class will not have any children who would need to override the functions of the base class. It is good practice.
There's a considerable difference when you have templates and start taking base class(es) as template parameter(s):
struct None {};
template<typename... Interfaces>
struct B : public Interfaces
{
void hello() { ... }
};
struct A {
virtual void hello() = 0;
};
template<typename... Interfaces>
void t_hello(const B<Interfaces...>& b) // different code generated for each set of interfaces (a vtable-based clever compiler might reduce this to 2); both t_hello and b.hello() might be inlined properly
{
b.hello(); // indirect, non-virtual call
}
void hello(const A& a)
{
a.hello(); // Indirect virtual call, inlining is impossible in general
}
int main()
{
B<None> b; // Ok, no vtable generated, empty base class optimization works, sizeof(b) == 1 usually
B<None>* pb = &b;
B<None>& rb = b;
b.hello(); // direct call
pb->hello(); // pb-relative non-virtual call (1 redirection)
rb->hello(); // non-virtual call (1 redirection unless optimized out)
t_hello(b); // works as expected, one redirection
// hello(b); // compile-time error
B<A> ba; // Ok, vtable generated, sizeof(b) >= sizeof(void*)
B<None>* pba = &ba;
B<None>& rba = ba;
ba.hello(); // still can be a direct call, exact type of ba is deducible
pba->hello(); // pba-relative virtual call (usually 3 redirections)
rba->hello(); // rba-relative virtual call (usually 3 redirections unless optimized out to 2)
//t_hello(b); // compile-time error (unless you add support for const A& in t_hello as well)
hello(ba);
}
The fun part of it is that you can now define interface and non-interface functions later to defining classes. That is useful for interworking interfaces between libraries (don't rely on this as a standard design process of a single library). It costs you nothing to allow this for all of your classes - you might even typedef B to something if you'd like.
Note that, if you do this, you might want to declare copy / move constructors as templates, too: allowing to construct from different interfaces allows you to 'cast' between different B<> types.
It's questionable whether you should add support for const A& in t_hello(). The usual reason for this rewrite is to move away from inheritance-based specialization to template-based one, mostly for performance reasons. If you continue to support the old interface, you can hardly detect (or deter from) old usage.
I will certainly include the Virtual keyword for the child class, because
i. Readability.
ii. This child class my be derived further down, you don't want the constructor of the further derived class to call this virtual function.

What is the effect of overriding a (regular) virtual method by a pure virtual method?

Let's say we have
class A {
public:
virtual int foo() { cout << "foo!"; }
}
class B : public A {
public:
virtual int foo() =0;
}
class C : public B {
public:
virtual int foo() { cout << "moo!"; }
}
Is this really overriding? I think this is actually overloading.
What is the meaning of making something like this, design-wise?
We got a base class A. Then we got an abstract derived class B which is derived from the concrete class A, and then a realization of B via C.
What are we doing here and does it make any sense?
Overloading would mean that you had two functions of the same name but with different parameters. That's not the case here.
Example:
int functionA() { /*...*/ };
int functionA(int someParameter) { /*...*/ };
Overriding means rewriting a function with the same parameters in a subclass. That is what you presented as an example.
That's the definition part. Now on to the design:
When you have a pure virtual function, concrete subclasses have to override it. So by adding a pure virtual function, you ensure that all subclasses provide the same set of functions (=interface). This seems to be the case in the sample code.
But it is not a very good example, as the concrete superclass already implements a default functionality for foo(). When there is an abstract subclass that redefines it to be purely virtual, it is a sign for me that the class hierarchy is flawed because a subclass (and the callers of foo()) usually should be able to fall back to the default implementation. It's a bit hard to explain with such an abstract example, but a hierarchy like this is a bit suspicious to my eye.
It seems to me that the only effect of the pure virtual method here is to make B an abstract class.
It's still overriding, because when you have a pointer p of type A* to instance of class C, p->foo() still calls C::foo()
Probably, the designer wanted to insert an abstract class in the hierarchy deriving from some concrete class, and force overriding of the method in subclasses. I don't think it's terribly wise.
You're saying that classes deriving from B must implement int foo();. You might want to do something like this to force other programmers to think about how they want foo() to behave, but I think it's a bad idea - in reality they're likely to implement by calling A::foo().
If you just want to make B abstract, give it a pure virtual destructor - you'll also need to provide an implementation of the destructor to avoid link error though.