Pure virtual inheritance, multiple inheritance, and C4505
Asked Answered
S

4

6

So I have an abstract base class with no abstract methods. In order to enforce abstractness, I've declared the (non-trivial) destructor as pure virtual:

class AbstractClass
{
public:
  AbstractClass()
  {
    std::wcout << L"AbstractClass::AbstractClass()" << std::endl;
  }
  virtual ~AbstractClass() = 0
  {
    std::wcout << L"AbstractClass::~AbstractClass()" << std::endl;
  }
};

class ConcreteClass : public AbstractClass
{
public:
  ConcreteClass()
  {
    std::wcout << L"ConcreteClass::ConcreteClass()" << std::endl;
  }
  virtual ~ConcreteClass()
  {
    std::wcout << L"ConcreteClass::~ConcreteClass()" << std::endl;
  }
};

This builds and works as expected; the output for a code block that simply defines an instance of ConcreteClass is


    AbstractClass::AbstractClass()
    ConcreteClass::ConcreteClass()
    ConcreteClass::~ConcreteClass()
    AbstractClass::~AbstractClass()

Now, when I have derive AbstractClass from another class used as an interface class, itself having a (trivial) virtual destructor (pure or otherwise), it still works:

class IAlpha
{
public:
  virtual ~IAlpha() = 0 {}
};

class AbstractClass : public IAlpha
{
public:
  AbstractClass()
  {
    std::wcout << L"AbstractClass::AbstractClass()" << std::endl;
  }
  virtual ~AbstractClass() = 0
  {
    std::wcout << L"AbstractClass::~AbstractClass()" << std::endl;
  }
};

class ConcreteClass : public AbstractClass
{
public:
  ConcreteClass()
  {
    std::wcout << L"ConcreteClass::ConcreteClass()" << std::endl;
  }
  virtual ~ConcreteClass()
  {
    std::wcout << L"ConcreteClass::~ConcreteClass()" << std::endl;
  }
};

The problem arises when I attempt to implement two different interfaces in this manner:

class IAlpha
{
public:
  virtual ~IAlpha() = 0 {}
};

class IBeta
{
public:
  virtual ~IBeta() = 0 {}
};

class AbstractClass : public IAlpha, public IBeta
{
public:
  AbstractClass()
  {
    std::wcout << L"AbstractClass::AbstractClass()" << std::endl;
  }
  virtual ~AbstractClass() = 0
  {
    std::wcout << L"AbstractClass::~AbstractClass()" << std::endl;
  }
};

class ConcreteClass : public AbstractClass
{
public:
  ConcreteClass()
  {
    std::wcout << L"ConcreteClass::ConcreteClass()" << std::endl;
  }
  virtual ~ConcreteClass()
  {
    std::wcout << L"ConcreteClass::~ConcreteClass()" << std::endl;
  }
};

At this point, when building, I receive the following warning:

warning C4505: 'AbstractClass::~AbstractClass' :
unreferenced local function has been removed

Strangely enough, however, the output still shows AbstractClass::~AbstractClass() getting called.

Is this a bug in MSVC9 (VS 2008)? Can I safely ignore this warning?

Edit: I've tried separating the pure virtual method definitions from the class definition as well, as apparently the = 0 {} syntax is not actually valid. Unfortunately, C4505 still shows up, whether I specify inline or not.

Since I've found no way to #pragma out this warning just for these methods (the warning gets triggered from other parts of the code), I may have to remove the pure virtual specifier from AbstractClass and rely on making the constructors protected. Not an ideal solution, but it beats rearchitecting the class hierarchy to get around an erroneous warning.

Sisak answered 26/9, 2012 at 0:12 Comment(0)
P
3

This is a bug in MSVC++ 2010 and earlier. The code actually gets called even though the compiler claims to have removed the code. It seems to be fixed in MSVC++ 2012. Other compilers like gcc or clang do not emit a warning. The syntax "... = 0 {...}" is illegal according to the C++03 standard section 10.4.2 (even though MSVC++ does not complain) as it has already been pointed out:

Note: a function declaration cannot provide both a pure-specifier and a definition

However, defining a pure virtual destructor in general is not illegal and section 12.4.7 states:

A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly- declared) is virtual.

My way of disabling the warning is to add the following lines to the header:

#if defined(_MSC_VER) && (_MSC_VER <= 1600)
#  pragma warning(disable:4505)
#endif

If you want to disable the warnings more locally then #pragma warning( push ) and #pragma warning( pop ) might be of help. See http://msdn.microsoft.com/en-us/library/2c8f766e(v=vs.80).aspx

Since the code seems to get called you can ignore the warnings in my opinion.

Proliferous answered 1/8, 2013 at 15:36 Comment(1)
I'd be interested to know where this bug was reported so I can cite it.Busty
N
0

Did you try defining the destructors in a non-inline manner? Perhaps the warning is related to that.

Such as this code.

Nashbar answered 26/9, 2012 at 0:38 Comment(1)
I tried the code in your link; it gets the same warning even though, as before, it functions correctly when run.Sisak
C
0

The code should not compile. Pure virtual functions cannot be defined inside the class definition. Move the definition outside of the classes:

struct IAlpha {
  virtual ~IAlpha() = 0;
};
inline IAlpha::~IAlpha() {}
// similarly for the rest.

Besides that, the code is correct and should compile.

Cheesecloth answered 26/9, 2012 at 1:16 Comment(1)
Interesting; I didn't know that you couldn't combining the pure virtual specifier and the method body. Unfortunately, I tried it this way as well and the warning still shows up (see answer from jeffmagill).Sisak
V
0

You can't define the virtual function to inline.

Because the inline is in compile. The virtual is in runtime.

Vent answered 1/8, 2013 at 16:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.