I have three classes: B, D and G. D is a B and G is a D. Both B and D are abstract. B is from a third party.
B has a non-pure, virtual method that G needs to implement (to be a D). Can I and is it good practice to redefine/override a virtual function to be pure virtual?
Example:
class B // from a third party
{
public:
virtual void foo();
};
class D : public B
{
public:
void foo() override = 0; // allowed by gcc 4.8.2
virtual void bar() = 0;
};
class G : public D
{
public:
// forgot to reimplement foo
void bar() override;
};
int main()
{
G test; // compiler error is desired
}
To the question of "can I?" gcc allows it, but I do not have the terms/vocabulary to verify the behavior is part of the standard or is undefined and happens to work today.
You asked:
Can I override a virtual function with a pure virtual one?
The answer is: Yes, you can. From the C++11 standard:
10.4 Abstract classes
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 ]
If you compile the code with a more modern compiler then you'll get the following error messages that explain the problem
prog.cc:23:6: error: variable type 'G' is an abstract class
G test; // compiler error is desired
^
prog.cc:10:9: note: unimplemented pure virtual method 'foo' in 'G'
void foo() override = 0; // allowed by gcc 4.8.2
^
1 error generated.
As for the Standard then (10.3 Virtual functions)
11 A virtual function declared in a class shall be defined, or
declared pure (10.4) in that class, or both; but no diagnostic is
required (3.2).
Related
Consider following code:
class A {
public:
virtual void f() const = 0;
void callf() const { f(); }
};
class B : public A {
virtual void f() const { }
};
int main()
{
B x;
x.callf();
return 0;
}
Class B derives from the abstract base class A, but "hides" the implemented method f() as private member.
Still, the inherited member callf() is able to call f(), which was public in the base class.
The code compiles with no warning on g++ 10.1.0 and clang++ 11.1.0.
Is this a legal code, i.e., does the inherited callf() correctly see the private member f()?
Alternatively, would it be possible for the derived class B to implement the purely virtual methods of the base class, such that they can only be called by B (and friends)?
Is this a legal code, i.e., does the inherited callf() correctly see the private member f()?
Yes, it is legal code. From the compiler's point-of-view, the callf function is referencing the f function of its own class; the fact that that is a virtual function does not affect the scope (or accessibility) – only the implementation, which will be in the form of a call to a v-table entry. That v-table entry will be correctly interpreted at run time, when it is called via the derived class.
This question already has an answer here:
method in the derived class got executed without a *virtual* keyword in the referred class
(1 answer)
Closed 2 years ago.
Probably, i misunderstood c++ polymorphism(virtual function).
Please point me what i miss.
the source code is below
#include <iostream>
using namespace std;
class A {
public:
virtual void print(void) {
cout<<"class A"<<endl;
}
};
class B : public A {
public:
void print(void) {
cout<<"class B"<<endl;
}
};
class C : public B {
public:
void print(void) {
cout<<"class C"<<endl;
}
};
int main() {
A a;
B b;
C c;
A *pAa = &a;
A *pAb = &b;
A *pAc = &c;
B *pBc = &c;
pAa->print();
pAb->print();
pAc->print();
pBc->print(); // shouldn't be "class B"
return 0;
}
result
------------------------------
class A
class B
class C
class C // shouldn't be "class B"
my understanding is that
the last print statement should print "class B"
because pBc is a pointer of class B and the print function in class B is non virtual member function. i could not find the answer about this situation.
please tell me why or point me where i can find the answer and
understand c++ polymorphism in comprehension.
thanks.
If a function with a given signature is declared as virtual in a top-level base class, then the function is virtual in all derived classes no matter if it is marked with the keyword virtual (override, final) or not:
virtual function specifier
Then this function in the class Derived is also virtual (whether or not the keyword virtual is used in its declaration)
struct Base {
// Pure virtual function.
virtual void foo() const = 0;
};
struct A : public Base {
// Overriding virtual function, even if it
// is not marked as virtual (override, or final).
void foo() const {}
};
In A, adding the virtual specifier to foo() would only bring semantic value; it will be no functional difference whether virtual is omitted or not (unless someone changes the interface in Base).
Many static analyzers enforce(1) marking derived virtual functions with override or final, for two reasons:
semantics; clearly showing the given function is a virtual function (as per being defined so higher up in the inheritance chain), and
enforcement; if a function is marked as override and final but is not actually an overriding function, you will get a compiler error, which can be particularly useful to protect against mistakes when changing a base class interface (whilst forgetting which classes that actually implements this interface).
E.g.:
struct Base {
// Pure virtual function.
virtual void foo() const = 0;
};
struct A : public Base {
// Overriding virtual function.
void foo() const override {}
};
struct B final : public Base {
// Overriding (final) virtual function.
void foo() const final {}
// Error: Function does not override.
// void bar() const override {}
};
(1) E.g. Rule A10-3-1 in the Autsar C++14 Language Guidelines (safety-critical development in automotive) is categorized as a required rule: Virtual function declaration shall contain exactly one of the three specifiers:(1) virtual, (2) override, (3) final.
the print function in class B is non virtual member function
No. Since A::print is marked as virtual and B inherits from A, then B::print is virtual too; regardless of the keywork virtual is specified on it or not.
(emphasis mine)
If some member function vf is declared as virtual in a class Base, and
some class Derived, which is derived, directly or indirectly, from
Base, has a declaration for member function with the same
name
parameter type list (but not the return type)
cv-qualifiers
ref-qualifiers
Then this function in the class Derived is also virtual (whether or not the keyword virtual is used in its declaration) and overrides Base::vf (whether or not the word override is used in its declaration).
In this particular case, why do I have to define the non-pure virtual method in the base class in order to avoid a linker error?
This gives a linker error:
class A
{
public:
virtual ~A(){}
virtual void foo() = 0;
virtual void bar();
};
class B : public A
{
public:
void foo()
{
}
void bar()
{
}
};
int main()
{
B b;
}
Output:
/tmp/cc5E8Tit.o: In function `A::~A()':
:(.text._ZN1AD2Ev[_ZN1AD5Ev]+0x13): undefined reference to `vtable for
A' /tmp/cc5E8Tit.o:(.rodata._ZTI1B[_ZTI1B]+0x10): undefined reference
to `typeinfo for A' collect2: error: ld returned 1 exit status
But if i define the bar method in class A it links ok:
class A
{
public:
virtual ~A(){}
virtual void foo() = 0;
virtual void bar(){}
};
class B : public A
{
public:
void foo()
{
}
void bar()
{
}
};
int main()
{
B b;
}
... no linker error.
Why is this?
R Sahu already provided standard quote related to this, I will provide slightly longer explanation why error happens — sometimes you can get away with not defining functions if they are not used, but not in this case.
Virtual functions are always used. Their address is used in virtual tables which are built for each class with virtual functions and which are used for dynamic dispatch.
Linker emits an error, because base class A constructor sets up pointer to base class virtual table, virtual table contains pointer to bar and linker cannot find definition of bar member function to find its address.
From the C++11 Standard:
10.3 Virtual functions
11 A virtual function declared in a class shall be defined, or declared pure (10.4) in that class, or both; but no diagnostic is required (3.2).
It's OK to define a pure virtual function but it is not necessary.
It is necessary to define a virtual function if it is declared but not declared as pure virtual.
It's good that the linker complains even though the language does not require it to.
The answer is in the definition itself. A function is pure virtual if it is not defined. Then, if you don't flag it as pure virtual, you have to define it. It's a constraint of the C++ language.
According to Wikipedia, in this example:
struct Base {
virtual void some_func(float);
};
struct Derived : Base {
virtual void some_func(float) override;
};
I thought override was not a C++ keyword, so what does it really mean?
We can achieve the same thing without that keyword so why would anyone need it?
There is also the keyword final which does not yet work on VS2010 :
struct Base1 final { };
struct Derived1 : Base1 { }; // ill-formed because the class Base1
// has been marked final
In C++11, override and final are "identifiers with special meaning". They are not keywords and only acquire special meaning if used in a specific context (when declaring virtual functions).
The idea is to enable to compiler to catch certain types of errors by allowing the programmer to explicitly state their intent (e.g. to override an existing virtual function rather than create a new one).
Here is the relevant quote from the standard, with examples:
C++11 10.3 4 If a virtual function f in some class B is marked with the
virt-specifier final and in a class D derived from B a function D::f
overrides B::f, the program is ill-formed. [ Example:
struct B {
virtual void f() const final;
};
struct D : B {
void f() const; // error: D::f attempts to override final B::f
};
—end example ]
5 If a virtual function is marked with the virt-specifier override
and does not override a member function of a base class, the program
is ill-formed. [ Example:
struct B {
virtual void f(int);
};
struct D : B {
void f(long) override; // error: wrong signature overriding B::f
void f(int) override; // OK
};
—end example ]
Given the base class A and the derived class B:
class A {
public:
virtual void f() = 0;
};
class B : public A {
public:
void g();
};
void B::g() {
cout << "Yay!";
}
void B::f() {
cout << "Argh!";
}
I get errors saying that f() is not declared in B while trying do define void B::f(). Do I have to declare f() explicitly in B? I think that if the interface changes I shouldn't have to correct the declarations in every single class deriving from it. Is there no way for B to get all the virtual functions' declarations from A automatically?
EDIT: I found an article that says the inheritance of pure virtual functions is dependent on the compiler:
http://www.objectmentor.com/resources/articles/abcpvf.pdf
I'm using VC++2008, wonder if there's an option for this.
Do I have to declare f() explicitly in B?
Yes, you have to declare in the class' definition all virtual function of any base classes that you want to override in the class. As for why: That's just the way the C++ syntax is.
Note that the virtual keyword can be omitted for the declaration of overriding virtual functions:
class base {
virtual void f();
virtual void g();
};
class derived : public base {
virtual void f(); // overrides base::f()
void g(); // overrides base::g()
};
Note: A class declaration is this: class my_class;, while this class my_class { /* ... */ }; is a class definition. There's a limited number of things you can do with a class that's only been declared, but not defined. In particular, you cannot create instances of it or call member functions.
For more about the differences between declaration and definitions see here.
Ok, for the benefit of the "declaration vs. definition" debate happening in the comments, here is a quote from the C++03 standard, 3.1/2:
A declaration is a definition unless it [...] is a class name declaration
[...].
3.1/3 then gives a few examples. Amongst them:
[Example: [...]
struct S { int a; int b; }; // defines S, S::a, and S::b
[...]
struct S; // declares S
—end example]
To sum it up: The C++ standard considers struct S; to be a declaration and struct S { /*...*/ }; a definition. I consider this a strong backup of my interpretation of "declaration vs. definition" for classes in C++.
Yes, in C++ you have to explicitly clarify your intention to override the behavior of a base class method by declaring (and defining) it in the derived class. If you try to provide a new implementation in derived class without declaring it in class definition it will be a compiler error.
The C++ class declaration defines the content of the class. If you do not declare f() in B, it looks like you do not override it. B::f() can be implemented only if you declare it.
In your current code, you are just inheriting the function f() in class B and you do not redefine base class's member in derived class.
Is there no way for B to get all the
virtual functions' declarations from A
automatically?
If you do not mark the function f in A as pure virtual with =0, the function is automatically also present in any subclass.
class A {
public:
virtual void f(); // not =0!
};
class B : public A {
public:
void g();
};
void A::f() {
cout << "I am A::f!";
}
void B::g() {
cout << "Yay!";
}
Now:
B* b = new B();
b->f(); // calls A::f
By declaring a pure virtual function you are stating that your class is abstract and that you want to require all concrete derived classes to have an implementation of that function. A derived class which does not supply an implementation for the pure virtual function is an extension of the abstract base class and is, itself, an abstract class. Trying to instantiate an abstract class is, of course, an error.
Pure virtual functions allow you to define an interface "contract" that you expect all derived classes to adhere to. A client of that class can expect that any instantiated class with that interface implements the functions in the contract.
Another interesting tidbit... you may supply a body for a pure virtual function but it is still pure and must be overridden in a concrete derived class. The advantage to supplying the body is to provide base behavior while still forcing derived classes to implement the function. The overridden functions can then call the base function Base::F() just like other virtual functions. When the body is not defined, calling Base::F() on a pure virtual functions is an error.