繁体   English   中英

前向声明/包含模板类 - “不完整类型的无效使用”

[英]Forward Declarations/Includes with Template Classes - “invalid use of incomplete type”

我正在尝试创建一个模板类,其中有一个函数可以接收该模板的特定实例。 我做了以下人为的例子来说明这一点。

比方说,我有一个用模板化(通用)类型的数据标记的个人世界。 我有一个特定的个体,称为国王。 并且所有个人都应该能够在国王面前下跪。 一般来说,个人可以被标记为任何东西。 国王用数字标记(第一个、第二个国王)。

错误

g++ -g -O2 -Wall -Wno-sign-compare -Iinclude -DHAVE_CONFIG_H    -c -o Individual.o Individual.cpp
g++ -g -O2 -Wall -Wno-sign-compare -Iinclude -DHAVE_CONFIG_H    -c -o King.o King.cpp
In file included from King.h:3,
                 from King.cpp:2:
Individual.h: In member function ‘void Individual<Data>::KneelBeforeTheKing(King*)’:
Individual.h:21: error: invalid use of incomplete type ‘struct King’
Individual.h:2: error: forward declaration of ‘struct King’
make: *** [King.o] Error 1

Individual.h(Individual.cpp 为空)

//Individual.h
#pragma once
class King;
#include "King.h"
#include <cstdlib>
#include <cstdio>

template <typename Data> class Individual
{
protected:
    Data d;
    
public:

    void Breathe()
    {
        printf("Breathing...\n");
    };
    
    void KneelBeforeTheKing(King* king)
    {
        king->CommandToKneel();
        printf("Kneeling...\n");
    };
    
    Individual(Data a_d):d(a_d){};
};

王.h

//King.h
#pragma once
#include "Individual.h"
#include <cstdlib>
#include <cstdio>

class King : public Individual<int>
{
protected:

    void CommandToKneel();
    
public:
    
    King(int a_d):
        Individual<int>(a_d)
    {
        printf("I am the No. %d King\n", d);
    };
};

国王.cpp

//King.cpp
#include "King.h"
#include <string>

int main(int argc, char** argv)
{
    Individual<std::string> person("Townsperson");
    King* king = new King(1);
    king->Breathe();
    person.Breathe();
    person.KneelBeforeTheKing(king);
    
}

void King::CommandToKneel()
{
    printf("Kneel before me!\n");
}

生成文件

CXX = g++
CXXFLAGS = -g -O2 -Wall -Wno-sign-compare -Iinclude -DHAVE_CONFIG_H 
OBJS = Individual.o King.o

test: $(OBJS)
    $(CXX) -o $@ $^

clean:
    rm -rf $(OBJS) test
    
all: test
error: invalid use of incomplete type 'struct King'

这意味着您只声明了King而没有定义它。 您有循环包含问题( Individual.hKing.h包含)。 这篇文章应该对这个问题有所了解。

你的两个类 King 和 Individual 是非常紧密耦合的。

将它放在两个这样的标题中是行不通的,因为两者都需要彼此。

如果您的课程必须这样设计,那么:

  1. 首先定义类Individual但不实现KneelBeforeTheKing,只需声明该函数。

  2. 然后定义国王

  3. 然后实现上面的方法。

但是,您的设计可能完全错误。 例如,您的模板类有许多不依赖于 tamped 类型的方法,包括 KneelBeforeTheKing,应该从模板中重构出来。

嗯,这里的问题与模板并不真正相关。

您正在调用基类中后代的特殊功能。 这几乎总是一个糟糕的设计标志。

颠倒类怎么样? 像这样(可能包含错误):

template < typename PersonType >
class Person : PersonType
{
    public:
        void command_to_kneel() { PersonType::command_to_kneel(); }
        void kneel_before_king(Person<King>* king) { king->command_to_kneel(); }
        void breathe() {  } 
};

int main()
{
    Person<King> king;
    Person<Knight> knight;
    knight.kneel_before_king(&king);
}

您可以通过向类 King 添加另一个基类(例如 NobleBase)来打破依赖关系:

struct NobleBase
{
  virtual void KneelBefore() = 0;
};


class King : public Individual<int>,
             public NobleBase

并改变方法
void KneelBeforeTheKing(King* king)
对此
void KneelBeforeTheKing(NobleBase* king)

然后您需要包含 NobleBase 类的标头。

除了语法和编译器错误,我认为最大的问题是你的个人告诉国王告诉自己下跪。

void KneelBeforeTheKing(King* king)
{
    king->CommandToKneel();
    printf("Kneeling...\n");
};

正如 Let_Me_Be 指出的那样,这是设计问题而不是语法问题。 实际上,国王应该决定个人何时下跪,因此对 CommandToKneel() 的任何调用都来自国王本人是有道理的,并且个人集作为参数提供,以指定谁被命令。

语法问题是您正在尝试使用尚未定义的功能。 King 的所有前向声明所做的就是告诉 Individual 的头文件有一个名为 King 的类型。 那时编译器对 King 的成员一无所知,因为您没有包含声明这些成员的头文件,也没有在使用 King 之前的任何地方定义它。

然而,正如已经指出的那样,在其基类型(即个人)的声明中对派生类型(即 King)进行任何类型的引用都是糟糕的设计。 基类应该对其派生类型一无所知。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM