Why I have to redeclare a virtual function while overriding [C++]
Asked Answered
U

7

30
#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?

Uneasy answered 2/6, 2010 at 13:16 Comment(3)
What compiler error do you get?Accrete
Even though in this example we see an abstract base class, the question is valid in general, too.Serriform
I could, although without knowing what compiler you are using I might not get the same (or any) error :)Accrete
A
25

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.
Aria answered 2/6, 2010 at 13:22 Comment(3)
The = 0; at the end of the declaration means you HAVE to define it in the derived class. Not that you might want to.Salty
@Ben: You might decide that you don't want to instantiate that class in a specific project :) But you are correct. What I meant that instead of implementing it one level below in the hierarchy you might want to implement it even lowerAria
The redeclaration is needed because, [...] It makes the compiler's work easier - oh FFS C++, why not just make everyone write in assembly, it'd make the compiler's job way easierSapphera
S
12

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?

Salty answered 2/6, 2010 at 13:29 Comment(2)
Is HugeDuck == BigDuck? Is this a second derived class that you're proposing, or a typo? (or a derived class of BigDuck, or something else)?Porush
yes, but that's not OP's question. The question is why does BigDuck::quack() need to be declared. if BigDuck::quack() is defined, it must also be declared in the member-specification of BigDuck even tho quack() is already declared in Duck, regardless of whether Duck::quack() is pure virtual or not.Ender
S
7

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' )

Serriform answered 2/6, 2010 at 13:27 Comment(3)
This doesn't work (anymore?). Gives error: no declaration matches ‘void BigDuck::quack()’, using GCC 11.Federica
It seems you have to re-declare in any case (virtual or not), iff you want to implement the method in the derived class. But I'm not completely sure about the validity of that.Federica
I'll add a note that you have to read past the code to find that the code is an example of what does not compile.Serriform
P
2

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.

Peltast answered 2/6, 2010 at 13:18 Comment(5)
But surely the compiler knows to expect it in the implementation. What purpose does the extract declaration serve?Granger
@Matt The language standard says it is required - this hs nothing to do with abstract classes, all virtual functions (and indeed all functions) work that way.Junco
It's been several years since I did anything with C++ "in anger", but I'm pretty sure that the code is not actually providing an implementation for quack() but instead is either being ignored (since the compiler doesn't expect a method implementation) or implementing a new method (hiding/overload rather than override).Peltast
@Galactic It is providing an implementation in the derived class. It certainly isn't being ignored!Junco
Duh - I withdraw my statement. :) I meant the way he had it written, but of course it wouldn't compile so neither part of my statement is correct. If it won't compile, it's not being ignored or overloading.Peltast
M
2

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

Maxine answered 2/6, 2010 at 13:19 Comment(1)
Now that's a good argument for being able to not declare quack. But what's the argument for having to declare it?Serriform
J
2

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.

Junco answered 2/6, 2010 at 13:20 Comment(0)
F
1

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();
Felisha answered 2/6, 2010 at 13:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.