Предупреждение компилятора в C++ обрабатывает базовый класс по шаблону

Я получаю предупреждение компилятора, которое я не понимаю в том контексте. Когда я компилирую "Child.cpp" из следующего кода. (Не задавайтесь вопросом: Я снял изоляцию со своих объявлений класса к абсолютному минимуму, таким образом, содержание не будет иметь большого смысла, но Вы будете видеть более быструю проблему). Я получаю предупреждение с  Visual Studio 2003 и  Visual Studio 2008 на самом высоком уровне предупреждения.


Код

AbstractClass.h:

#include 

template
class AbstractClass
{
    public:
        virtual void Cancel(); // { std::cout << "Abstract Cancel" << std::endl; };
        virtual void Process() = 0;
};

// Outside definition. If I comment out this and take the inline
// definition like above (currently commented out), I don't get
// a compiler warning.
template
void AbstractClass::Cancel()
{
    std::cout << "Abstract Cancel" << std::endl;
}

Child.h:

#include "AbstractClass.h"

class Child : public AbstractClass
{
    public:
        virtual void Process();
};

Child.cpp:

#include "Child.h"
#include 

void Child::Process()
{
    std::cout << "Process" << std::endl;
}

Предупреждение

Класс "Ребенок" получен из "AbstractClass". В "AbstractClass" существует открытый метод "AbstractClass:: Отмена ()". Если я определяю метод за пределами тела класса (как в коде, Вы видите), я получаю предупреждение компилятора...

AbstractClass.h (7): предупреждение C4505: 'AbstractClass:: Отмена': не имеющая ссылки локальная функция была удалена с [T=int]

... когда я компилирую "Child.cpp". Я не понимаю это, потому что это - государственная функция, и компилятор не может знать если я более поздняя ссылка этот метод или нет. И в конце я ссылаюсь на этот метод, потому что я называю его в main.cpp и несмотря на это предупреждение компилятора, этот метод работы, если я компилирую и связываю все файлы и выполняю программу:

//main.cpp
#include 
#include "Child.h"

int main()
{
    Child child;
    child.Cancel();  // Works, despite the warning
}

Если я действительно определяю Отмену () функция как встроенную (Вы видите его как прокомментированный код в AbstractClass.h), то я не получаю предупреждение компилятора. Конечно, мои работы программы, но я хочу понять это предупреждение, или это - просто ошибка компилятора?

Кроме того, если не реализуют AbsctractClass как шаблонный класс (только для тестовой цели в этом случае), я также не получаю предупреждение компилятора...?


Если я делаю невиртуальную функцию, я не получаю предупреждение компиляции для той невиртуальной функции, но все ответы до сих пор не включают виртуальный материал. Попробуйте это:

template
class AbstractClass
{
    public:
        virtual void Cancel(); // { std::cout << "Abstract Cancel" << std::endl; };
        virtual void Process() = 0;
        void NonVirtualFunction();
};

//...

template
void AbstractClass::NonVirtualFunction()
{
    std::cout << "NonVirtualFunction" << std::endl;
}

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

13
задан Peter Mortensen 5 July 2016 в 08:15
поделиться

4 ответа

Код в обычных, не шаблонных методах класса компилируется, когда компилятор встречает код для метода.

Для шаблонных классов это иное. Код находится в заголовке, поэтому, если компилятор будет компилировать его каждый раз, когда он встречает код, это будет означать, что этот метод компилируется снова и снова, даже если он не вызывается вашим кодом. Предположим, что child.h включен в 1000 других файлов. Вы хотите, чтобы компилятор скомпилировал метод Cancel 1000 раз или только при фактическом вызове Cancel?

child.cpp включает child.h, но не вызывает метод Cancel. Поэтому Cancel не компилируется (хотя мне кажется странным, что вы получаете предупреждение об этом).

main.cpp также включает child.h, и на этот раз он вызывает метод Cancel, который является сигналом компилятору для компиляции метода. Наконец, компоновщик найдет все скомпилированные экземпляры метода Cancel и объединит их.

0
ответ дан 2 December 2019 в 01:57
поделиться

Шаблоны инстанцируются до генерации кода. Это означает, что компилятору необходимо знать конкретный класс, используемый в шаблоне, чтобы сгенерировать код для этого шаблона. Поэтому, когда вы определяете метод класса шаблона в отдельном блоке, его определение неизвестно во время инстанцирования шаблона.

Предупреждение, скорее всего, означает, что код для AbstractClass::Cancel не генерируется в блоке, который вы использовали для определения AbstractClass::Cancel. Методы шаблонных классов генерируются только после их использования (т.е. ссылки, вызова), в отличие от кода обычного метода, который генерируется сразу после его появления.

Если вы попытаетесь вызвать AbstractClass::Cancel из функции в AbstractClass.cpp, где определен Cancel, предупреждение должно исчезнуть.

0
ответ дан 2 December 2019 в 01:57
поделиться

Создание виртуального шаблона функции незаконно. См. Вопрос о переполнении стека Законно ли виртуально сделать специализацию шаблона функции? .

-2
ответ дан 2 December 2019 в 01:57
поделиться

Я не думаю, что это предупреждение сделано намеренно. Компилятор ошибочно полагает, что функция является локальной для единицы трансляции, но функция совсем не такова. Вы используете сгенерированную функцию в другой единице перевода из main , поэтому функция используется . Различные способы, которые вы придумали для исчезновения предупреждения, кажутся разными способами обойти ошибочный путь в компиляторе.

Отличие от виртуальных состоит в том, что виртуальные функции могут быть созданы даже без их использования. Это происходит, когда их класс обычно неявно создается. Стандарт заявляет, что действителен (выделено мной)

Реализация не должна неявно создавать экземпляр шаблона функции, шаблона члена, невиртуального функция-член, класс-член или статический член данных шаблона класса, который не требует создания экземпляра. Не указано, создает ли реализация неявно экземпляр виртуальной функции-члена шаблона класса, если в противном случае виртуальная функция-член не была бы создана.

В этом случае есть два неявных экземпляра этой той же виртуальной функции. Один в Child.h был создан без всякого использования, и поэтому компилятор считает эту функцию бесполезной.Но поскольку эта же функция используется в другом месте (в main.cpp ), это предупреждение явно противоречит друг другу.

3
ответ дан 2 December 2019 в 01:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: