纯虚拟继承、多重继承和C4505

Pure virtual inheritance, multiple inheritance, and C4505

本文关键字:C4505 多重继承 虚拟 继承      更新时间:2023-10-16

所以我有一个没有抽象方法的抽象基类。为了增强抽象性,我已经将(非平凡的)析构函数声明为纯虚拟的:

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;
}
};

这将按预期构建和工作;简单定义ConcreteClass实例的代码块的输出是

AbstractClass::AbstractClass()混凝土类::混凝土类()混凝土类::~ConcreteClass()AbstractClass::~AbstractClass()

现在,当我从另一个用作接口类的类派生AbstractClass时,它本身有一个(琐碎的)虚拟析构函数(纯的或其他的),它仍然有效:

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;
}
};

当我试图以这种方式实现两个不同的接口时,问题就出现了:

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;
}
};

此时,在构建时,我收到以下警告:

警告C4505:"AbstractClass::~AbstractClass":未引用的局部函数已被删除

然而,奇怪的是,输出仍然显示AbstractClass::~AbstractClass()被调用。

这是MSVC9(VS 2008)中的一个错误吗?我可以放心地忽略这个警告吗?

编辑:我也尝试过将纯虚拟方法定义与类定义分离,因为显然= 0 {}语法实际上是无效的。不幸的是,无论我是否指定inline,C4505仍然显示。

由于我找不到#pragma仅针对这些方法发出此警告的方法(警告是从代码的其他部分触发的),我可能不得不从AbstractClass中删除纯虚拟说明符,并依赖于使构造函数受到保护。这不是一个理想的解决方案,但它比重新安排类层次结构来绕过错误的警告要好。

这是MSVC++2010及更早版本中的一个错误。代码实际上得到调用,即使编译器声称已删除代码。似乎是在MSVC++2012中固定。其他编译器,如gcc或clang,不会发出警告。根据C++03标准第10.4.2节,语法"…=0{…}"是非法的(尽管MSVC++没有抱怨),正如已经指出的那样:

注意:函数声明不能同时提供纯说明符和定义

然而,定义纯虚拟析构函数通常并不违法,第12.4.7节规定:

析构函数可以声明为虚拟的(10.3)或纯虚拟的(10.4);如果该类或任何派生类的任何对象都是在程序,应定义析构函数。如果一个类有基类使用虚拟析构函数,其析构函数(无论是用户还是隐式声明)是虚拟的。

我禁用警告的方法是在标题中添加以下行:

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

如果您想在本地禁用警告,那么#pragma warning( push )#pragma warning( pop )可能会有所帮助。看见http://msdn.microsoft.com/en-us/library/2c8f766e(v=vs.80).aspx

由于代码似乎被调用了,在我看来,您可以忽略这些警告。

您是否尝试以非内联方式定义析构函数?也许这个警告与此有关。

比如这个代码。

代码不应该编译。不能在类定义内部定义纯虚拟函数。将定义移出类:

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

除此之外,代码是正确的,应该编译。

不能将虚拟函数定义为内联函数。

因为内联正在编译中。虚拟机正在运行时。