Итак, у меня есть абстрактный базовый класс без абстрактных методов. Чтобы усилить абстрактность, я объявил (нетривиальный) деструктор как чисто виртуальный:
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
и полагаться на защиту конструкторов. Не идеальное решение, но оно превосходит реструктуризацию иерархии классов, чтобы обойти ошибочное предупреждение.
Это ошибка в 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
Поскольку код кажется вызванным, вы можете игнорировать предупреждения, по моему мнению.
Вы пытались определить деструкторы не встроенным способом? Возможно, предупреждение связано с этим.
Такие как этот код.
Код не должен компилироваться. Чистые виртуальные функции не могут быть определены внутри определения класса. Переместите определение за пределы классов:
struct IAlpha {
virtual ~IAlpha() = 0;
};
inline IAlpha::~IAlpha() {}
// similarly for the rest.
Кроме того, код правильный и должен компилироваться.
Вы не можете определить виртуальную функцию для встраивания.
Потому что встроенный в компиляции.
Виртуальный находится во время выполнения.