C++模板基类的编译器警告

eik*_*ike 13 c++ templates base-class compiler-warnings

我得到了一个编译器警告,我在这种情况下不理解.当我从以下代码编译"Child.cpp"时.(不要错过:我将我的课堂声明剥离到最低限度,所以内容没有多大意义,但你会更快地看到问题).我在最高警告级别上使用Visual Studio 2003Visual Studio 2008收到警告.


代码

AbstractClass.h:

#include <iostream>

template<typename T>
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<typename T>
void AbstractClass<T>::Cancel()
{
    std::cout << "Abstract Cancel" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

Child.h:

#include "AbstractClass.h"

class Child : public AbstractClass<int>
{
    public:
        virtual void Process();
};
Run Code Online (Sandbox Code Playgroud)

Child.cpp:

#include "Child.h"
#include <iostream>

void Child::Process()
{
    std::cout << "Process" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

警告

"Child"类派生自"AbstractClass".在"AbstractClass"中,有公共方法"AbstractClass :: Cancel()".如果我在类体之外定义方法(就像在你看到的代码中那样),我会得到编译器警告......

AbstractClass.h(7):警告C4505:'AbstractClass :: Cancel':用[T = int]删除了未引用的局部函数

...当我编译"Child.cpp"时.我不明白这一点,因为这是一个公共函数,编译器无法知道我以后是否引用了这个方法.并且,最后,我引用了这个方法,因为我在main.cpp中调用它,尽管有这个编译器警告,但是如果我编译并链接所有文件并执行程序,这个方法也有效:

//main.cpp
#include <iostream>
#include "Child.h"

int main()
{
    Child child;
    child.Cancel();  // Works, despite the warning
}
Run Code Online (Sandbox Code Playgroud)

如果我将Cancel()函数定义为内联(您在AbstractClass.h中将其视为注释代码),那么我不会收到编译器警告.当然我的程序有效,但我想了解这个警告或者这只是一个编译器错误?

此外,如果不将AbsctractClass实现为模板类(在这种情况下仅用于测试目的)我也没有得到编译器警告......?


如果我创建一个非虚函数,我不会得到该非虚函数的编译警告,但到目前为止所有答案都不包含虚拟内容.试试这个:

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

//...

template<typename T>
void AbstractClass<T>::NonVirtualFunction()
{
    std::cout << "NonVirtualFunction" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

知道的答案对我有所帮助,但我不认为这个问题得到了充分的回答.

Tom*_*rly 5

我在这里找不到正确的答案:如果您在模板化类中有一个纯虚拟方法,Visual Studio将错误地报告此警告。在这种情况下,其他编译器(如gcc和clang)似乎没有报告此警告。

模板类或非模板类中的纯虚拟方法是完全合理的,并且通常是一个好主意-将方法声明为纯虚拟,迫使您在派生类中实现该方法。

我没有在任何地方找到对此错误的引用-我不在Microsoft开发人员程序中,也许有人可以提交此错误?

  • 可以通过内联定义虚拟函数来解决警告。 (2认同)

Pat*_*ick 0

当编译器遇到该方法的代码时,将编译普通非模板化类方法中的代码。

对于模板类来说这是不同的。代码位于标头中,因此如果编译器每次遇到代码时都会对其进行编译,则意味着该方法会被一遍又一遍地编译,即使您的代码没有调用它。假设 child.h 包含在 1000 个其他文件中。您希望编译器编译 Cancel 方法 1000 次,还是仅在实际调用 Cancel 时编译?

child.cpp 包含 child.h,但不调用 Cancel 方法。因此 Cancel 不会被编译(尽管我觉得很奇怪你会收到这样的警告)。

main.cpp中还包含了child.h,这次它调用了Cancel方法,这是编译器编译该方法的信号。最后,链接器将找到 Cancel 方法的所有已编译实例并合并它们。