Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does a virtual function override a non-virtual function of the same name in a base class?

Tags:

c++

Is the following standard conforming? Can you cite the section?

struct A
{
    virtual void func() = 0;
};

struct B
{
    void func(){}
};

struct C : public A, public B
{
    virtual void func(){ B::func(); }
};

I'm getting a strange compiler warning in VS2010 in equivalent but more complicated code pointing to func's declaration in the derived-most class: warning C4505: unreferenced local function has been removed. I have no idea why the compiler thinks a virtual function declared in a class is a local; however I can't repro that warning in a simpler example.

Edit:

I figured out a small repro case for the warning. I think I was going down the wrong path assuming it was related to function hiding. Here's the repro case:

template<typename T>
struct C
{
    int GetType() const;
    virtual int func() const;   // {return 4;}  //  Doing this inline removes the warning <--------------
};

template<typename T>
int C<T>::GetType() const
{
    return 0;
}

template<>
int C<int>::GetType() const
{
    return 12;
}

template<typename T> 
int C<T>::func() const
{
    return 3; 
}

//  Adding the following removes the warning <--------------------
//  template<>
//  int C<int>::func() const
//  {
//      return 4;
//  }

I'm fairly sure this is just a VS2010 bug.

like image 879
David Avatar asked May 07 '12 19:05

David


People also ask

Can a virtual function override?

Virtual functions are member functions whose behavior can be overridden in derived classes. As opposed to non-virtual functions, the overriding behavior is preserved even if there is no compile-time information about the actual type of the class.

Can I override a non-virtual function?

You cannot override a non-virtual or static method. The overridden base method must be virtual , abstract , or override . An override declaration cannot change the accessibility of the virtual method. Both the override method and the virtual method must have the same access level modifier.

Can virtual function be overridden in its derived class?

The virtual keyword can be used when declaring overriding functions in a derived class, but it is unnecessary; overrides of virtual functions are always virtual. Virtual functions in a base class must be defined unless they are declared using the pure-specifier.

Is it mandatory to override virtual methods of base class?

When the method is declared as virtual in a base class, and the same definition exists in a derived class, there is no need for override, but a different definition will only work if the method is overridden in the derived class. Two important rules: By default, methods are non-virtual, and they cannot be overridden.


2 Answers

The code is well-formed. C::func overrides A::func. B::func is an unrelated function. The spec reads (10.3/2):

If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list, cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides111 Base::vf.

C::func has the same name as A::func and A::func is virtual, therefore C::func overrides A::func. B::func has no relation to A::func; I don't know that there is any language in the spec that expressly addresses that scenario.

The Visual C++ 11 Beta compiler does not emit any warnings or errors for this code.

like image 188
James McNellis Avatar answered Oct 27 '22 00:10

James McNellis


Normally virtual functions can't be eliminated by the linker as dead-code, because their addresses have to appear in the vtable. However, if the vtable for struct C was determined to be dead code (which could happen if all constructors are also dead code), then that last remaining reference can be eliminated too.

Because the function is declared inline, this dead code removal optimization doesn't have to wait until link time; it can be done by the compiler. The Standard says (see section 7.1.2):

An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case (3.2). [ Note: A call to the inline function may be encountered before its definition appears in the translation unit. — end note ] If the definition of a function appears in a translation unit before its first declaration as inline, the program is ill-formed. If a function with external linkage is declared inline in one translation unit, it shall be declared inline in all translation units in which it appears; no diagnostic is required. An inline function with external linkage shall have the same address in all translation units. A static local variable in an extern inline function always refers to the same object. A string literal in the body of an extern inline function is the same object in different translation units. [ Note: A string literal appearing in a default argument is not in the body of an inline function merely because the expression is used in a function call from that inline function. — end note ] A type defined within the body of an extern inline function is the same type in every translation unit.

If the compiler can determine the function is never used in this translation unit, it knows that any translation unit that does use the function must contain its own identical definition, and will generate the code. So it can skip code generation just as if it didn't have external linkage at all.

Generating a warning is completely pointless, however, since there will be a high number of false positives (when the inline function IS odr-used and code generated in some other compilation unit).

like image 21
Ben Voigt Avatar answered Oct 27 '22 00:10

Ben Voigt