C++ class 使用后的声明

C++ class declaration after using it

我想创建一个带有参数的方法,该参数链接到稍后声明的 Enemy。 这是我的代码:

#include <iostream>
#include <vector>
using namespace std;
class Weapon{
    public:
        int atk_points;
        string name;
        string description;
        void Attack(Entity target){
            
        };
};
class Armor{
    public:
        int hp_points;
        string name;
        string description;
        int block_chance;
};
class Entity{
    public:
        int hp;
        int atk;
        string name;
        vector<Weapon> weapons;
        vector<Armor> armors;
};

我试图搜索答案,但没有找到任何有用的信息。 这是错误日志:

prog.cpp:9:15: error: ‘Entity’ has not been declared
   void Attack(Entity target){

你不能。

你必须早点申报。但是,在某些情况下,您可以稍后定义它。

要转发声明一个 class,请在使用前写下:

class Entity;

问题是编译器不知道Entity在你用作参数类型的地方是什么。所以你需要告诉编译器 Entity 是一个 class 类型。

有两种方法可以解决这个问题,下面给出了两种方法:

方法一

解决这个问题,您需要做以下两件事:

  1. 为 class Entity 提供前向声明。
  2. Attack 的参数设为引用类型,这样我们就可以避免不必要的参数复制,而且因为我们提供的是成员函数的定义,而不仅仅是声明。
class Entity; //this is the forward declaration
class Weapon{
    public:
        int atk_points;
        string name;
        string description;
//------------------------------v------------>target is now an lvalue reference
        void Attack(const Entity& target){
            
        };
};

Working demo

方法二

解决这个问题的另一种方法是,您可以只在 class 中提供成员函数 Attack' 的声明,然后在 class [=12] 之后提供定义=]的定义如下图:

class Entity;   //forward declaration
class Weapon{
    public:
        int atk_points;
        string name;
        string description;
//------------------------------v----------->this time using  reference is optional
        void Attack(const Entity& target);  //this is a declaration
};
//other code here as before


class Entity{
    public:
        int hp;
        int atk;
        string name;
        vector<Weapon> weapons;
        vector<Armor> armors;
};

//implementation after Entity's definition
void Weapon::Attack(const Entity& target)
{
    
}

Working demo

在c++中,这样的代码无法编译:

class A {
    void fooa(B) {}
};

class B {
    void foob(A) {}
};

但是这样的代码是可以编译的,我们可以这样改代码:

class A { };
class B { };
void fooa(A *, B) {}
void foob(B *, A) {}

它有效,没有任何东西是递归的。

所以,我认为更改为引用不是一个好主意。直接的方法就是使用一些技巧。例如,将 Entity 更改为 auto。就像那样:void Attack(auto target)。 更重要的是,用c++20,你可以定义一个概念attackable,让Entity is attackable,我很喜欢。