C++ C++;类转发声明

C++ C++;类转发声明,c++,class,forward-declaration,C++,Class,Forward Declaration,当我尝试编译此代码时,我得到: 52 C:\Dev-Cpp\Projektyyy\strategy\Tiles.h invalid use of undefined type `struct tile_tree_apple' 46 C:\Dev-Cpp\Projektyyy\strategy\Tiles.h forward declaration of `struct tile_tree_apple' 我的部分代码: class tile_tree_apple; class tile_t

当我尝试编译此代码时,我得到:

52 C:\Dev-Cpp\Projektyyy\strategy\Tiles.h invalid use of undefined type `struct tile_tree_apple' 
46 C:\Dev-Cpp\Projektyyy\strategy\Tiles.h forward declaration of `struct tile_tree_apple' 
我的部分代码:

class tile_tree_apple;

class tile_tree : public tile
{
      public:
          tile onDestroy() {return *new tile_grass;};
          tile tick() {if (rand()%20==0) return *new tile_tree_apple;};
          void onCreate() {health=rand()%5+4; type=TILET_TREE;};        
};

class tile_tree_apple : public tile
{
      public:
          tile onDestroy() {return *new tile_grass;};
          tile tick() {if (rand()%20==0) return *new tile_tree;};
          void onCreate() {health=rand()%5+4; type=TILET_TREE_APPLE;}; 
          tile onUse() {return *new tile_tree;};       
};
我真的不知道该怎么办,我寻找解决方案,但我找不到任何与我的问题相似的。。。事实上,我有更多的类与家长“瓷砖”,这是好的,以前

编辑:

我决定将所有返回的类型更改为指针以避免内存泄漏,但现在我得到了:

27 C:\Dev-Cpp\Projektyyy\strategy\Tiles.h ISO C++ forbids declaration of `tile' with no type 
27 C:\Dev-Cpp\Projektyyy\strategy\Tiles.h expected `;' before "tick"
它只在基类中,其他一切都可以。。。tile类中返回*tile的每个函数都有此错误

一些代码:

class tile
{
      public:
          double health;
          tile_type type;
          *tile takeDamage(int ammount) {return this;};
          *tile onDestroy() {return this;};
          *tile onUse() {return this;};
          *tile tick() {return this};
          virtual void onCreate() {};
};

除了声明指向对象的指针之外,还需要完整的定义

最好的解决方案是将实现移动到单独的文件中。

如果必须将其保留在标题中,请将定义移动到两个声明之后:

class tile_tree_apple;

class tile_tree : public tile
{
  public:
      tile onDestroy();
      tile tick();
      void onCreate();        
};

class tile_tree_apple : public tile
{
  public:
      tile onDestroy();
      tile tick();
      void onCreate(); 
      tile onUse();       
};

tile tile_tree::onDestroy() {return *new tile_grass;};
tile tile_tree::tick() {if (rand()%20==0) return *new tile_tree_apple;};
void tile_tree::onCreate() {health=rand()%5+4; type=TILET_TREE;};        

tile tile_tree_apple::onDestroy() {return *new tile_grass;};
tile tile_tree_apple::tick() {if (rand()%20==0) return *new tile_tree;};
void tile_tree_apple::onCreate() {health=rand()%5+4; type=TILET_TREE_APPLE;}; 
tile tile_tree_apple::onUse() {return *new tile_tree;};       
重要

您有内存泄漏:

tile tile_tree::onDestroy() {return *new tile_grass;};

将在堆上创建一个对象,以后不能销毁它,除非您进行一些丑陋的黑客攻击。此外,您的对象将被切片如果不执行此操作,请返回指针。

为了编译
新t
t
必须是完整类型。在您的情况下,当您在
tile\u tree::tick
的定义中说
new tile\u tree\u apple
时,
tile\u tree\u apple
是不完整的(它已被转发声明,但它的定义稍后在您的文件中)。尝试将函数的内联定义移动到单独的源文件中,或者至少将它们移动到类定义之后

比如:

class A
{
    void f1();
    void f2();
};
class B
{
   void f3();
   void f4();
};

inline void A::f1() {...}
inline void A::f2() {...}
inline void B::f3() {...}
inline void B::f4() {...}

当您以这种方式编写代码时,这些方法中对A和B的所有引用都保证引用完整类型,因为不再有正向引用了

转发声明是一种“不完整类型”,使用这种类型只能实例化指向它的指针,或在函数声明中引用它(即函数原型中的参数或返回类型)。在代码的第52行中,您试图实例化一个对象


此时,编译器不知道对象的大小和构造函数,因此无法实例化对象。

类tile\u tree\u apple应在单独的.h文件中定义

tta.h:
#include "tile.h"

class tile_tree_apple : public tile
{
      public:
          tile onDestroy() {return *new tile_grass;};
          tile tick() {if (rand()%20==0) return *new tile_tree;};
          void onCreate() {health=rand()%5+4; type=TILET_TREE_APPLE;}; 
          tile onUse() {return *new tile_tree;};       
};

file tt.h
#include "tile.h"

class tile_tree : public tile
{
      public:
          tile onDestroy() {return *new tile_grass;};
          tile tick() {if (rand()%20==0) return *new tile_tree_apple;};
          void onCreate() {health=rand()%5+4; type=TILET_TREE;};        
};

另一件事:返回一个tile而不是tile引用不是一个好主意,除非tile是一个原始的或非常“小”的类型。

问题是
tick()
需要知道
tile\u tree\u apple
的定义,但它所拥有的只是一个向前声明。您应该将声明和定义分开,如下所示:

tile_tree.h

#ifndef TILE_TREE_H
#define TILE_TREE_H
#include "tile.h"

class tile_tree : public tile
{
public:
    tile onDestroy();
    tile tick();
    void onCreate();
};

#endif
tile_tree.cpp

tile tile_tree::onDestroy() {
    return *new tile_grass;
}

tile tile_tree::tick() {
     if (rand() % 20 == 0)
         return *new tile_tree_apple;
}

void tile_tree::onCreate() {
    health = rand() % 5 + 4;
    type = TILET_TREE;
}
除了您有一个主要问题:您正在分配内存(使用
new
),然后复制分配的对象并返回副本。这称为内存泄漏,因为程序无法释放它所使用的内存。不仅如此,您还将
平铺树
复制到
平铺
中,这将丢弃使
平铺树
不同于
平铺
的信息;这叫做切片

您需要返回指向新
磁贴的指针,并确保在某个时间点调用
delete
,以释放内存:

tile* tile_tree::tick() {
     if (rand() % 20 == 0)
         return new tile_tree_apple;
}
更好的做法是返回一个智能指针,为您处理内存管理:

#include <memory>

std::shared_ptr<tile> tile_tree::tick() {
     if (rand() % 20 == 0)
         return std::make_shared<tile_tree_apple>();
}
#包括
std::shared_ptr tile_tree::tick(){
如果(rand()%20==0)
返回std::make_shared();
}

要执行
*新的tile\u tree\u apple
应该调用
tile\u tree\u apple
的构造函数,但在这里,编译器对
tile\u tree\u apple
一无所知,因此不能使用构造函数

如果你把

tile tile_tree::tick() {if (rand()%20==0) return *new tile_tree_apple;};

在具有类tile_tree_apple定义的单独cpp文件或包含具有该定义的头文件中,一切都将正常工作。

尽可能使用前向声明

假设您要定义一个新类
B
,该类使用类
a
的对象

  • B
    仅使用指向
    A
    的引用或指针。使用转发声明,则不需要包含
    。这将反过来加快一点编译速度

    class A ;
    
    class B 
    {
      private:
        A* fPtrA ;
      public:
        void mymethod(const& A) const ;
    } ;
    
  • B
    派生自
    A
    B
    显式(或隐式)使用类
    A
    的对象。然后需要包括

    #include <A.h>
    
    class B : public A 
    {
    };
    
    class C 
    {
      private:
        A fA ;
      public:
        void mymethod(A par) ;   
    }
    
    #包括
    B类:公共A
    {
    };
    C类
    {
    私人:
    A fA;
    公众:
    无效方法(A par);
    }
    
  • 我有这个:

    class paulzSprite;
    ...
    
    struct spriteFrame
    {
        spriteFrame(int, int, paulzSprite*, int, int);
        paulzSprite* pSprite; //points to the sprite class this struct frames
        static paulzSprite* pErase; //pointer to blanking sprite
        int x, y;
        int Xmin, Xmax, Ymin, Ymax; //limits, leave these to individual child classes, according to bitmap size
        bool move(int, int);
        bool DrawAt(int, int);
        bool dead;
    };
    
    spriteFrame::spriteFrame(int initx, int inity, paulzSprite* pSpr, int winWidth, int winHeight)
    {
        x = initx;
        y= inity;
        pSprite = pSpr;
        Xmin = Ymin = 0;
        Xmax = winWidth - pSpr->width;
        Ymax = winHeight - pSpr->height;
        dead = false;
    }
    

    和原来的问题一样悲伤。 仅通过将paulzSprite的定义移到spriteFrame的定义之后的来解决。编译器不应该比这更聪明吗(VC++,VS 11 Beta版)


    顺便说一句,我完全同意Clifford上面的评论“指针不会导致内存泄漏,糟糕的编码会导致内存泄漏”。我想,其他许多新的“智能编码”功能也是如此,它们不应该取代理解您实际要求计算机做什么。

    这不是真的。查阅标准。例如,如果T是不完整类型,则可以声明(但不定义)一个接受T的函数。您还可以声明对T的引用。这应该很有用,函数的返回类型也可能不完整。对于不完整的类型,您可以做很多事情。如何在不实例化对象的情况下实例化指针?@Luchian:在这种情况下:
    tile\u tree\u apple*tta\u ptr
    实例化类型为
    tile\u tree\u apple*
    的指针,当然它并不指向有效的对象。关键是,您可能有这样一个指针作为类的成员,该类稍后在构造函数中实例化对象,但无论如何,在代码中完整类型可见的点处。@Kerrek:可能,但可能与此讨论无关