Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pure virtual inheritance, multiple inheritance, and C4505

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.

like image 864
somethingdotjunk Avatar asked Sep 26 '12 00:09

somethingdotjunk


1 Answers

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.

like image 174
user1225999 Avatar answered Oct 10 '22 15:10

user1225999