繁体   English   中英

C++ 类前向声明

[英]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_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;};       
};

我真的不知道该怎么做,我搜索了解决方案,但找不到任何与我的问题类似的东西......实际上,我有更多的父级“tile”类,之前还可以......

编辑:

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

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() {};
};

尽可能使用前向声明。

假设您想定义一个使用类A对象的新类B

  1. B仅使用A引用或指针。 使用前向声明,则不需要包含<Ah> 这将反过来加快编译速度。

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

     #include <Ah> class B : public A { }; class C { private: A fA ; public: void mymethod(A par) ; }

为了编译new TT必须是完整类型。 在您的情况下,当您在tile_tree::tick的定义中说new tile_tree_apple时, tile_tree_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 行,您试图实例化一个object

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

我有这个:

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 上面的评论“指针不会导致内存泄漏,糟糕的编码会导致内存泄漏”。 恕我直言,这适用于许多其他新的“智能编码”功能,它们不应替代理解您实际要求计算机执行的操作。

问题是tick()需要知道tile_tree_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 ),然后复制分配的对象并返回副本。 这称为内存泄漏,因为您的程序无法释放它使用的内存。 不仅如此,您tile_tree复制到tile ,这会丢弃使tile_treetile不同的信息; 这称为切片

你想要的是返回一个指向新tile的指针,并确保你在某个时候调用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>();
}

类 tile_tree_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 是原始类型或非常“小”的类型。

除了声明指向对象的指针之外,要执行任何其他操作,您需要完整的定义。

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

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

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;};

将在堆上创建一个对象,之后您无法销毁该对象,除非您进行一些丑陋的黑客攻击。 此外,您的对象将被切片。 不要这样做,返回一个指针。

要执行*new tile_tree_apple的构造tile_tree_apple应该叫,但在这个地方编译器一无所知tile_tree_apple ,所以不能使用构造。

如果你把

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

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

暂无
暂无

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

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