C++类前向声明

noi*_*cat 13 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' 
Run Code Online (Sandbox Code Playgroud)

我的代码的一部分:

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;};       
};
Run Code Online (Sandbox Code Playgroud)

我真的不知道该怎么做,我搜索了解决方案,但我找不到任何与我的问题相似的东西......实际上,我有更多的课程与父母"瓷砖",这是好的之前... Thanx任何帮助.

编辑:

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

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"
Run Code Online (Sandbox Code Playgroud)

它只在基类中,其他一切都没问题... 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() {};
};
Run Code Online (Sandbox Code Playgroud)

小智 17

尽可能使用前向声明.

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

  1. B仅使用引用或指针A.使用前向声明然后您不需要包括<A.h>.这将反过来加快编译速度.

    class A ;
    
    class B 
    {
      private:
        A* fPtrA ;
      public:
        void mymethod(const& A) const ;
    } ;
    
    Run Code Online (Sandbox Code Playgroud)
  2. B派生自AB明确地(或隐含地)使用类的对象A.然后你需要包括<A.h>

    #include <A.h>
    
    class B : public A 
    {
    };
    
    class C 
    {
      private:
        A fA ;
      public:
        void mymethod(A par) ;   
    }
    
    Run Code Online (Sandbox Code Playgroud)


Arm*_*yan 15

为了new T编译,T必须是完整的类型.在你的情况下,当你new tile_tree_apple在定义里面说tile_tree::tick,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() {...}
Run Code Online (Sandbox Code Playgroud)

当您以这种方式编写代码时,这些方法中对A和B的所有引用都保证引用完整类型,因为没有更多的前向引用!

  • @kittyPL:指针不会导致内存泄漏,编码不良会导致内存泄漏. (8认同)
  • @kittyPL:使用[智能指针](http://en.wikipedia.org/wiki/Smart_pointer)以避免内存泄漏 (4认同)
  • @KerrekSB:它只需要继续定义; 把它放在声明上没有任何效果. (3认同)

Cli*_*ord 8

前向声明是一个" 不完整类型 ",你可以用这种类型做的唯一事情就是实例化一个指向它的指针,或者在函数声明中引用它(即函数原型中的参数或返回类型).在代码的第52行中,您尝试实例化一个对象.

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

  • 对于不完整类型,您还可以执行更多操作. (2认同)

小智 6

我有这个:

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;
}
Run Code Online (Sandbox Code Playgroud)

...

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

顺便说一句,我完全同意克利福德上面的评论"指针不会导致内存泄漏,编码不良会导致内存泄漏".恕我直言,许多其他新的"智能编码"功能也是如此,它不应该成为理解你实际要求计算机做什么的替代品.


Jon*_*rdy 5

问题是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
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

除非您有一个主要问题:您正在分配内存(使用new),然后复制分配的对象并返回副本。这称为内存泄漏,因为您的程序无法释放它使用的内存。不仅如此,您还将 a 复制tile_tree到 a 中tile,这会丢弃与 atile_tree不同的信息tile;这称为切片

您想要的是返回一个指向 new 的指针tile,并确保您delete在某个时候调用以释放内存:

tile* tile_tree::tick() {
     if (rand() % 20 == 0)
         return new tile_tree_apple;
}
Run Code Online (Sandbox Code Playgroud)

更好的是返回一个智能指针,它将为您处理内存管理:

#include <memory>

std::shared_ptr<tile> tile_tree::tick() {
     if (rand() % 20 == 0)
         return std::make_shared<tile_tree_apple>();
}
Run Code Online (Sandbox Code Playgroud)