views:

167

answers:

5

When a method is declared as virtual in a class, its overrides in derived classes are automatically considered virtual as well, and the C++ language makes this keyword virtual optional in this case:

class Base {
    virtual void f();
};
class Derived : public Base {
    void f(); // 'virtual' is optional but implied.
};

My question is: What is the rationale for making virtual optional?

I know that it is not absolutely necessary for the compiler to be told that, but I would think that developers would benefit if such a constraint was enforced by the compiler.

E.g., sometimes when I read others' code I wonder if a method is virtual and I have to track down its superclasses to determine that. And some coding standards (Google) make it a 'must' to put the virtual keyword in all subclasses.

+1  A: 

Since the language can't enforce "good" style, C++ generally doesn't even try. At least IMO, it's open to question whether including redundant specifiers like this is good style in any case (personally, I hate when they're there).

(At least parts of) Google's coding standards may make sense under some circumstances, but as far as C++ in general goes, are generally considered mediocre advice at best. To an extent, they even admit that -- some of them they openly state are only really there to fit with their old code. Other parts they don't admit so directly, and (to be entirely honest) that argument wouldn't support some of their standards anyway (i.e., some of it seems to lack real justification).

Jerry Coffin
It isn't that the language "can't", but rather that it is against C++ philosophy. A compiler can detect a great variety of style violations, including whether "virtual" was reused in the derived class.
Michael Aaron Safyan
@Michael: Perhaps I stated it poorly, but my intent was to say that it can't enforce good style in general, so it frequently doesn't try, even in cases where it clearly could (enforce something some people consider good style).
Jerry Coffin
+2  A: 

Yeah, it would really be nicer to make the compiler enforce the virtual in this case, and I agree that this is a error in design that is maintained for backwards compatibility.

However there's one trick that would be impossible without it:

class NonVirtualBase {
  void func() {};
};

class VirtualBase {
  virtual void func() = 0;
};

template<typename VirtualChoice>
class CompileTimeVirtualityChoice : public VirtualChoice {
  void func() {}
};

With the above we have compile time choice wether we want virtuality of func or not:

CompileTimeVirtualityChoice<VirtualBase> -- func is virtual
CompileTimeVirtualityChoice<NonVirtualBase> -- func is not virtual

... but agreed, it's a minor benefit for the cost of seeking a function's virtuality, and myself, I always try to type virtual everywhere where applicable.

Kornel Kisielewicz
Think you'd like to remove `= 0` from `NonVirtualBase` :)
Matthieu M.
@Matthieu -- good catch! I'm rather sleepy today xD
Kornel Kisielewicz
+3  A: 

Weak point in design, I agree. I also think that'd be really nice if there was a different syntax for two different things:

  1. Declaring a virtual function. I.e. the function that may be overridden in derived class. (This thing actually adds a new function entry in the vtable.)
  2. Overriding a virtual function in the derived class.

With current C++ rules when overriding a function - it's easy to screw things. If you mistype the function name (or make a mistake in its parameters list) - then you actually do (1) instead of (2).

And you have no error/warning. Just get the surprise at run-time.

valdo
One of the things that Object Pascal got right...
Kornel Kisielewicz
Agreed, I think it stems from Bjarne Stroustrup and the committee desire to have as small possible a set of keywords... thus reusing the same for different things. In the same vein, I really don't appreciate not to have a warning whenever shadowing occurs :/
Matthieu M.
A: 

That is a good question, and I certainly agree that it is good style to redeclare a method virtual in the derived class if it has been declared virtual in the base class. While there are some languages that build style into the language (e.g. Google Go and, to some extent, Python), C++ is not one of those languages. While it certainly is possible for a compiler to detect that a derived class does not reuse the keyword "virtual" for something declared "virtual" in a base class (or, more importantly, that the derived class declares a function of the same name as the base class and it has not been declared virtual in the base class), there are, in fact, settings on many compilers to issue warnings (and even error messages) in the event that this happens. At this stage, though, it would not be practical to institute such a requirement in the language as there exists too much code that is not that strict. Moreover, developers can always choose to be more stringent than the language and can turn up compiler warning levels.

Michael Aaron Safyan
+5  A: 

As a related note, in C++0x you have the option of enforcing being explicit with your overrides via the new attribute syntax.

struct Base {
  virtual void Virtual();
  void NonVirtual();
};

struct Derived [[base_check]] : Base {
  //void Virtual(); //Error; didn't specify that you were overriding
  void Virtual [[override]](); //Not an error
  //void NonVirtual [[override]](); //Error; not virtual in Base
  //virtual void SomeRandomFunction [[override]](); //Error, doesn't exist in Base
};

You can also specify when you intend to hide a member via the [[hiding]] attribute. It makes your code somewhat more verbose, but it can catch a lot of annoying bugs at compile time, like if you did void Vritual() instead of void Virtual() and ended up introducing a whole new function when you meant to override an existing one.

Dennis Zickefoose