Why I have to redeclare a virtual function while overriding [C++] - c++

#include <iostream>
using namespace std;
class Duck {
public:
virtual void quack() = 0;
};
class BigDuck : public Duck {
public:
// void quack(); (uncommenting will make it compile)
};
void BigDuck::quack(){ cout << "BigDuckDuck::Quack\n"; }
int main() {
BigDuck b;
Duck *d = &b;
d->quack();
}
The code above doesn't compile. However, when I declare the virtual function
in the subclass, then it compiles fine.
If the compiler already has the signature of the function that the subclass will override, then why is a redeclaration required?
Any insights?

The redeclaration is needed because:
The standard says so.
It makes the compiler's work easier by not climbing up the hierarchy to check if such function exists.
You might want to declare it lower in the hierarchy.
In order to instantiate the class the compiler must know that this object is concrete.

If you change:
virtual void quack() = 0;
to
virtual void quack();
It will compile without implementing quack() in HugeDuck.
the = 0; at the end of the function declaration is essentially saying that all BigDucks will quack, but that it has to be implemented by each derived duck. By removing the = 0; the BigDuck quack will get called unless you implement quack in HugeDuck.
EDIT: To clarify the = 0; is saying that the derived class will have the definition for the function. In your example it is expecting HugeDuck to define quack(), but as you have it commented it out it does not.
As a side note, since all ducks can quack perhaps your original Duck class that we can not see should implement quack() instead?

Because C++ separates 'declaration' from 'polymorphism': any function needs a declaration for the compiler, regardless if it's virtual or not.
Your example doesn't go far enough, it has the 'abstract class' problem: a BigDuck cannot be instantiated because it has no implementation of quack in it's interface.
Generalizing the problem, we can declare the base function not pure virtual:
class Duck { public: virtual void quack(){} };
class BigDuck : public Duck {};
// WRONG: undeclared method definition
void BigDuck::quack(){ cout << "QUACK!"; }
In here, the compiler will complain that it has a symbol BigDuck::quack that wasn't declared. This has nothing to do with abstract classes or anything.
(Note: gcc says:
error: no 'void BigDuck::q()' member function declared in class 'BigDuck'
)

The definition of Quack() in your base class is "abstract" - it has no implementation. This tells the compiler that your derived class must implement it. Failure to do so is a compilation error.

BigDuck could be another abstract class and you might not want to implement quack until you get to the base class ReallyBigDuck.

Until you provide an implementation, all classes that inherit from a class that contains Pure Virtual Function are abstract - they cannot be instantiated. In order to provide such an implementation, you must declare the function in the class.

Declaring the methods in each classes will tell the compiler that class provides the different implementation for the method.
Also,
in case you want to create the objects of BigDuck on stack then how will compiler should know the signature of quack().
BigDuck aDuck;
aDuck.quack();

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.

Virtual function and inheritance in C++

The code segment below works fine:
#include <iostream>
#include <string>
using namespace std;
class HelpInterface {
public:
void getHelp();
};
class Applicaiton : public HelpInterface {
public:
void getHelp() {
cout << "General help";
}
};
int main(void) {
Applicaiton applicaiton;
applicaiton.getHelp();
}
Make the getHelp function virtual in HelpInterface class and I will get a linker error:
class HelpInterface {
public:
virtual void getHelp();
};
If I make an empty implemenation of getHelp as below things will work again:
class HelpInterface {
public:
virtual void getHelp() {};
};
Can someone please help me understand why virtual throws a linker error unless I have an implementation for getHelp in the base class and why a non-virtual function with no implementation works just fine? In this example, the base function never gets called.
Here is a screenshot of VS2013 with the linker error:
If you want your base class method to be virtual and provide no implementation, you must set it equal to zero like this:
class HelpInterface {
public:
virtual void getHelp() = 0;
};
This is known as a pure virtual method. It has the effect of making your class abstract and forcing all of its derived classes to provide an implementation of the method. Consequently, take note that you will no longer be able to create an instance of the base class because it is abstract.
When a method is in the base class but isn't virtual the linker will not actually reference the implementation of the method if you don't have an explicit call to that method on either a pointer/reference to the base type (On an instance of the derived class) or an instance of the base type.
Virtual functions can be implemented a number of different ways, and are implementation specific. One of the most common is by using a virtual table. (Also known by virtual method table, virtual function table, virtual call table, dispatch table, vtable, or vftable), and I'm pretty sure your compiler (VS2013) uses this method of implementing virtual functions.
A virtual table is a table of function pointers for the virtual member functions. The class instance would contain a pointer to the table that the class belongs to.
When you make a function virtual the linker tries to put it into the virtual table for that type. It doesn't matter whether you call it or not or instantiate a base class (also an implementation specific detail).
As qexyn has already answered, to get around that you declare the method as pure virtual by adding = 0 after the virtual function declaration. This tells the linker to put a null pointer in the virtual function table for the class. You can also declare the virtual function pure virtual and also provide an implementation. This forces the derived classes to implement that function, but allows them to choose to use the default method.
The reason for this is that your base class definition is using indirection to get the actual function for Application.
This is often implemented with a function pointer, but in any case there could be a derived class that doesn't override the base class implementation.
Although this isn't usually reproducible that is simply because member functions are implicitly declared inline and when the implementation is visible an optimizing compiler will do exactly that; inline the function. The proof is in the optimization.
What you want, is to make sure that every derived class from your base implements getHelp(). This is a common idiom and is a core language feature. You want a "pure virtual function". This will make your base class an "abstract base class" which is actually a synonym for "interface" in object-oriented jibber-jabber.
The way to do this in C++ is with a special member-function specific syntax after all of the member function qualifiers (I'm using trailing return types here cause I think they're pretty):
class base{
public:
virtual auto func() -> void = 0;
};
This specifies that base is an abstract base class with a pure virtual function func() that all classes derived from it will implement.
In your case you would write:
class HelperInterface{
public:
virtual void getHelp() = 0; // probably want const qualifier
};
And just leave Application as it is.
You learn something every day, huh?

Should a virtual function essentially have a definition?

Is it essential to have a definition for a virtual function?
Consider this sample program below:
#include <iostream>
using namespace std;
class base
{
public:
void virtual virtualfunc();
};
class derived : public base
{
public:
void virtualfunc()
{
cout << "vf in derived class\n";
}
};
int main()
{
derived d;
return 0;
}
This gives the link-error:
In function base::base():: undefined reference to vtable for base
I do not have the definition for the virtual function in base class. Why is this error occurring even though I have not explicitly invoked the virtual function?
The interesting thing which I find is that if I do not instantiate an object of class derived, the link error is no longer there. Why is this? What has instantiation got to do with the above link error?
The ISO C++ Standard specifies that all virtual methods of a class that are not pure-virtual must be defined.
Reference:
C++03 Standard: 10.3 Virtual functions [class.virtual]
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).
So either you should make the function pure virtual or provide a definition for it.
If you are using gcc, You might get some weird errors if you fail to follow this standard specification. The gcc faq doccuments it as well:
The ISO C++ Standard specifies that all virtual methods of a class that are not pure-virtual must be defined, but does not require any diagnostic for violations of this rule [class.virtual]/8. Based on this assumption, GCC will only emit the implicitly defined constructors, the assignment operator, the destructor and the virtual table of a class in the translation unit that defines its first such non-inline method.
Therefore, if you fail to define this particular method, the linker may complain about the lack of definitions for apparently unrelated symbols. Unfortunately, in order to improve this error message, it might be necessary to change the linker, and this can't always be done.
The solution is to ensure that all virtual methods that are not pure are defined. Note that a destructor must be defined even if it is declared pure-virtual [class.dtor]/7.
You need to provide an implementation of a virtual function ( with its default behaviour ) unless you define the function to be "pure virtual".
So your example could be:
class base
{
public:
void virtual virtualfunc() {} //intentionally do nothing;
};
or
class base
{
public:
void virtual virtualfunc()=0; //pure virtual;
};
You either need to provide a definition, or mark it as abstract/pure-vitual.
void virtual virtualfunc() = 0;
In response to the error about the vtable: the virtual command in this case tells c++ to produce a virtual table of the methods in the base class. In this way when you use polymorphism, C++ is able to replace the base class virtual methods with the methods from the derived class with the same name during run time. This error is telling the user that this replacement is not possible. To fix this error, you will either need to implement the method or set it as pure virtual by adding "=0" at the end of the definition.
In response to the edits: The reason you are not getting an error when you instantiate the object as a base class is because the base class does not need to access the virtual table. On the other hand if you actually try to use this method, you should get an error since no implementation exists. In other words even though you can instantiate an object of the base class its not a complete class.
Yes you would need a body, but perhaps what you are referring to is called a pure virtual functions, which would not need a definition in the base class.
The syntax to define those is as follows:
void virtual virtualfunc() = 0;

Appended '= x' after a method declaration in c++

In C++, when a method is declared, I've noticed that sometime the method may have an assignement appended to it.
Could anyone tell me what this is?
For example:
virtual void MyMethod () = 0;
What doe the '= 0' mean. :)
Thanks everyone !!!
It means it's a pure virtual function, i.e. no actual definition of it is available in this class and it must be overridden in a subclass. It's not actually an assignment as such, zero is the only value you can "assign".
And this is C++ syntax; in C# the same would be accomplished with the abstract keyword.
In C++ this means that the method is a pure virtual method.
This means that an instance of this particular class-type cannot be instantiated. You can only create instances of classes derived from this, which override all pure virtual methods in the base class.
A base class with pure virtual methods defines an interface that derived classes have to implement, and is not meant to be used on its own.
Contrary to what calmh claims, as far as I know pure virtual functions can be implemented and they can be called explicitly.
#include <cstdio>
class A
{
public:
virtual void foo() const = 0; //pure virtual
};
void A::foo() const { puts("A::foo"); }
class B: public A
{
public:
virtual void foo() const { puts("B::foo"); }
};
int main()
{
//A a; //this would be an error - main point of having pure virtual functions
B b;
b.foo();
b.A::foo();
}
Usually one wouldn't do this, though, except perhaps if the virtual destructor is pure in a base class (in this case it has to be defined).
In C#, that is a syntax error.
If you meant C++, see calmh's answer.

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.