在从抽象类继承的模板类中正确使用未定义类型

时间:2016-04-12 11:06:23

标签: c++ templates visual-c++ abstract-class forward-declaration

我有一个头文件(比如说 the_foo.h ),它定义/声明了以下类:

// \file the_foo.h

class FooBase
{
    virtual size_t bar_size() = 0;
};

template<class Bar>
class Foo : public FooBase
{
    size_t  bar_size()  { return sizeof(Bar); }
};

class TheBar;       // TheBar forward declaration

class TheFoo : public Foo<TheBar>
{
};

使用MS vc14(Visual Studio 2015)进行编译时,我注意到以下行为:

  1. 包含 the_foo.h 并定义TheBar的任何cpp文件,例如:

    #include "the_foo.h" class TheBar {}; // TheBar definition

    编译就好了。然而,

  2. 包含 the_foo.h 不定义 TheBar的任何cpp文件,例如:

    #include "the_foo.h"

    无法编译错误:the_foo.h(11): error C2027: use of undefined type 'TheBar'

    上面编译的cpp文件包含一行:包含标题,不再包含代码 删除虚拟成员函数声明virtual size_t bar_size() = 0;确实可以解决错误 感谢Sam Varshavchik的回答,这段代码使用gcc 5.3.1编译得很好,所以这个问题显然是编译器特有的。

  3. 我的问题是:

    • 为什么编译失败的情况(2),TheBar只是前向声明?
    • 有没有办法让case(2)在vc14下成功编译,即没有TheBar的明确定义,哪个类需要在某些cpp文件中保持不透明?

    PS:我编辑了这个问题的代码示例,以便明确究竟是什么原因导致了问题中描述的问题。原始代码示例(在Sam Varshavchik的回答中引用)可能确实误导了问题的实际原因,并因此导致了问题范围之外的答案和评论。

2 个答案:

答案 0 :(得分:1)

您的测试用例编译时没有遇到gcc 5.3.1:

的问题
$ cat t.C
class FooBase
{
public:
    FooBase()          {}
    virtual ~FooBase() {}
};

template<class Bar>
class Foo : public FooBase
{
public:
    Foo()   { sizeof(Bar); bar = new Bar; }
    ~Foo()  { sizeof(Bar); delete bar; }
    Bar*    bar;
};

class TheBar;

class TheFoo : public Foo<TheBar>
{
public:
    TheFoo();
    ~TheFoo();
};
[mrsam@octopus tmp]$ g++ -c -o t.o t.C
[mrsam@octopus tmp]$ 

这里的答案似乎是&#34;你正在使用一个没有正确编译它的旧C ++编译器&#34;。

答案 1 :(得分:0)

当您尝试在class TheBar类的构造函数和析构函数中构造或删除Foo时,编译器会搜索该// foobase.h class FooBase { public: FooBase() {} virtual ~FooBase() {} }; template<class Bar> class Foo : public FooBase { public: Foo() { bar = new Bar; } ~Foo() { delete bar; } private: Bar* bar; }; class TheBar; class TheFoo : public Foo<TheBar> { public: TheFoo() {}; ~TheFoo() {}; }; 的定义。这意味着它需要在那时实现,否则它不知道该怎么做。

如果制作以下示例:

第一个标题:

// thebar.h

class TheBar {};

下一个标题

// foo_main.cxx

// #include "thebar.h" // Including this include makes the program run
#include "foobase.h"

int main()
{
    TheFoo thefoo;
    return 0;
}

以下主要文件:

./foobase.h:14:32: error: allocation of incomplete type 'TheBar'
        Foo()  { bar = new Bar; }

然后你的编译器会告诉你什么是错的(只显示第一个错误):

thebar.h

包括 ddlRegisters.Click(); SelectElement selector = new SelectElement(ddlRegisters); selector.SelectByIndex(1); String regSelect = selector.Options[1].Text.ToString(); Console.WriteLine("The User Selected "+regSelect+"."); 将解决问题。