David
David

Reputation: 28178

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

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.

Upvotes: 6

Views: 592

Answers (3)

Ben Voigt
Ben Voigt

Reputation: 283921

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

Upvotes: 1

Matthieu M.
Matthieu M.

Reputation: 300409

Let me google it for you.

function : unreferenced local function has been removed

The given function is local and not referenced in the body of the module; therefore, the function is dead code.

The compiler did not generate code for this dead function.

The compiler statically determined that the function was unused, so it did not generate code for that function and warns you that you have useless code. A bit more involved than the usual unused variable warning, but about the same effect: dead code smells.

Upvotes: 0

James McNellis
James McNellis

Reputation: 355357

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.

Upvotes: 3

Related Questions