views:

234

answers:

6

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.

+4  A: 

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++.

sbi
Actually, both of what you mentioned are class declarations. A declaration with no body is a forward-declaration. A class definition is the implementation of the class declaration (the function implementations in .cpp files).
tames
@tames: Actually, you're wrong. A forward declaration is the only kind of class declaration we have in C++. (Yes, the "forward" is redundant.) A class definition is what, among other stuff, contains member function declarations (and sometimes for inline functions defined in the class definition, member function definitions. What you write in the cpp file are mostly member function definitions (plus the definition of static class members declared in the class definition). See http://stackoverflow.com/questions/1410563/1410632#1410632 and http://stackoverflow.com/questions/671925/671936#671936.
sbi
@sbi: This is an interesting subject. My understanding, and most documentation I find, refers to it as a class declaration; and as a declaration it can occur within multiple compilation units (as long as it is identical), whereas a class definition (my usage) can only appear once. However, some documentation says that the full class declaration `class C {...}` is both a declaration and a definition; and a forward declaration allows the use of the class name but the class isn't considered fully declared yet.
tames
@tames: If most docs indeed describe it the way you say, then most docs describe it wrong. In C++ (and that's important, because the rules are different for different languages, in some aspects even subtly different for C vs. C++) `class x;` is a _class declaration_ (and as such can be repeated at will), while `class x { /*...*/ };` is a _class definition_ (and as such must only appear once per translation unit). TTBOMK, that's the only correct application of the terms "declaration" and "definition" to classes in C++.
sbi
@sbi: I don't want to belabor the point, but the full class declaration specifies the class "type" and appears in every compilation unit that it is used (every file that includes the header), so thus, it appears multiple times (not allowed for definitions)... but the class definition appears in one and only one source file. A forward declaration is only a special case declaration to allow a class to be referenced before it is fully declared.
tames
@tames: `<sigh>` A class definition (`class x {};`) must only appear once per translation unit, not multiple times. A class declaration (`class x;`) may appear multiple times. Since they won't fit in here, I'll paste a few relevant quotes from the C++03 standard into my answer. I very much hope this would settle this discussion ones and for all.
sbi
A: 

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.

hype
Well, he wrote "I get errors saying that f() is not declared in B while trying do define void B::f()", so I guess it's safe to assume that he is trying to define `B::f()`.
sbi
absolutely...i just tried to give him some additional information because what he's trying to do is redefine base class method in his derived class.
hype
+2  A: 

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.

Little Bobby Tables
+4  A: 

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.

Naveen
Okay, my bad, I forgot to mention that the function is _pure_ virtual, now it should be clear that it'll have to be defined (not overriden) by the derived class, and I still get the error.
neuviemeporte
@neuviemeporte: The same rule holds for the pure virtual also. Imagine a case where you are building class hierarchy like this A->B->C. In this case it doesn't make sense to automatically define the virtual (or pure virtual function) in B, as B may itself be an abstract class adding more pure virtual methods to A.
Naveen
Should the declarations in B also have the virtual keyword? I've seen this done both ways.
neuviemeporte
@neuviemeporte: need not. But I find it is a good practice to write the function as virtual. You do not gain anything by omitting it. Once it is declared as virtual in the base class it remains virtual in the derived classes also.
Naveen
A: 

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
Danvil
A: 

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.

tames