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.
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.
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.
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.
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.
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.
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 classBase
and in a classDerived
, derived directly or indirectly fromBase
, a member functionvf
with the same name, parameter-type-list, cv-qualification, and ref-qualifier (or absence of same) asBase::vf
is declared, thenDerived::vf
is also virtual (whether or not it is so declared) and it overrides111Base::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.
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. Astatic
local variable in anextern inline
function always refers to the same object. A string literal in the body of anextern 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 anextern 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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With