Чистое виртуальное наследование, множественное наследование и C4505

Итак, у меня есть абстрактный базовый класс без абстрактных методов. Чтобы усилить абстрактность, я объявил (нетривиальный) деструктор как чисто виртуальный:

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 :: ConcreteClass ()
ConcreteClass :: ~ 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 {} синтаксис на самом деле не действителен. К сожалению, C4505 все еще обнаруживается, указываю ли я inline или нет.

Так как я не нашел способа #pragma Это предупреждение только для этих методов (предупреждение вызывается из других частей кода), возможно, мне придется удалить чистый виртуальный спецификатор из AbstractClass и полагаться на защиту конструкторов. Не идеальное решение, но оно превосходит реструктуризацию иерархии классов, чтобы обойти ошибочное предупреждение.

6

Решение

Это ошибка в MSVC ++ 2010 и более ранних версиях. Код на самом деле получает
вызывается, хотя компилятор утверждает, что удалил код. Это кажется
исправлено в MSVC ++ 2012. Другие компиляторы, такие как gcc или clang, не выдают предупреждение.
Синтаксис «… = 0 {…}» является недопустимым в соответствии с разделом 10.4.2 стандарта C ++ 03 (даже несмотря на то, что 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

Поскольку код кажется вызванным, вы можете игнорировать предупреждения, по моему мнению.

3

Другие решения

Вы пытались определить деструкторы не встроенным способом? Возможно, предупреждение связано с этим.

Такие как этот код.

0

Код не должен компилироваться. Чистые виртуальные функции не могут быть определены внутри определения класса. Переместите определение за пределы классов:

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

Кроме того, код правильный и должен компилироваться.

0

Вы не можете определить виртуальную функцию для встраивания.

Потому что встроенный в компиляции.
Виртуальный находится во время выполнения.

0
По вопросам рекламы [email protected]