C++ 类前向声明

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9119236/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:18:59  来源:igfitidea点击:

C++ class forward declaration

c++classforward-declaration

提问by noisy cat

When I try to compile this code i get:

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

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' 

some part of my code:

我的代码的一部分:

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

I dont really know what to do, I searched for the solution but I couldnt find anything simmilar to my problem... Actually, i have more classes with parent "tile" and It was ok before... Thanx for any help.

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

EDIT:

编辑:

I decided to change all returned types to pointers to avoid memory leaks, but now I got:

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

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"

Its only in base class, everything else is ok... Every function in tile class which return *tile has this error...

它仅在基类中,其他一切正常... tile 类中返回 *tile 的每个函数都有此错误...

Some code:

一些代码:

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

回答by kumaran

Use forward declaration when possible.

尽可能使用前向声明。

Suppose you want to define a new class Bthat uses objects of class A.

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

  1. Bonly uses references or pointers to A. Use forward declaration then you don't need to include <A.h>. This will in turn speed a little bit the compilation.

    class A ;
    
    class B 
    {
      private:
        A* fPtrA ;
      public:
        void mymethod(const& A) const ;
    } ;
    
  2. Bderives from Aor Bexplicitely (or implicitely) uses objects of class A. You then need to include <A.h>

    #include <A.h>
    
    class B : public A 
    {
    };
    
    class C 
    {
      private:
        A fA ;
      public:
        void mymethod(A par) ;   
    }
    
  1. B仅使用指向A. 使用前向声明,则不需要包含<A.h>. 这将反过来加快编译速度。

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

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

回答by Armen Tsirunyan

In order for new Tto compile, Tmust be a complete type. In your case, when you say new tile_tree_appleinside the definition of tile_tree::tick, tile_tree_appleis incomplete (it has been forward declared, but its definition is later in your file). Try moving the inline definitions of your functions to a separate source file, or at least move them after the class definitions.

为了new T编译,T必须是完整的类型。在你的情况,当你说new tile_tree_apple的定义中tile_tree::ticktile_tree_apple是不完整的(已宣布向前,但它的定义是以后在你的文件)。尝试将函数的内联定义移动到单独的源文件中,或者至少将它们移动到类定义之后。

Something like:

就像是:

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

When you write your code this way, all references to A and B in these methods are guaranteed to refer to complete types, since there are no more forward references!

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

回答by Clifford

The forward declaration is an "incomplete type", the only thing you can do with such a type is instantiate a pointerto it, or reference it in a function declaration(i.e. and argument or return type in a function prototype). In line 52 in your code, you are attempting to instantiate an object.

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

At that point the compiler has no knowledge of the object's size nor its constructor, so cannot instantiate an object.

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

回答by Paul Pignon

I had this:

我有这个:

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

...

...

Got the same grief as in the original question. Only solved by moving the definition of paulzSprite to afterthat of spriteFrame. Shouldn't the compiler be smarter than this (VC++, VS 11 Beta)?

得到与原始问题相同的悲伤。只能通过将paulzSprite的定义移到spriteFrame之后解决。编译器不应该比这更聪明吗(VC++,VS 11 Beta)?

And btw, I wholeheartedly agree with Clifford's remark above "Pointers don't cause memory leaks, poor coding causes memory leaks". IMHO this is true of many other new "smart coding" features, which should not become a substitute for understanding what you are actually asking the computer to do.

顺便说一句,我完全同意 Clifford 上面的评论“指针不会导致内存泄漏,糟糕的编码会导致内存泄漏”。恕我直言,这适用于许多其他新的“智能编码”功能,它们不应替代理解您实际要求计算机执行的操作。

回答by Jon Purdy

The problem is that tick()needs to know the definition of tile_tree_apple, but all it has is a forward declaration of it. You should separate the declarations and definitions like so:

问题是tick()需要知道 的定义tile_tree_apple,但它所拥有的只是它的前向声明。您应该像这样分开声明和定义:

tile_tree.h

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

Exceptyou have a major problem: you're allocating memory (with new), then copying the allocated object and returning the copy. This is called a memory leak, because there's no way for your program to free the memory it uses. Not only that, but you're copying a tile_treeinto a tile, which discards the information that makes a tile_treedifferent from a tile; this is called slicing.

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

What you want is to return a pointer to a new tile, and make sure you call deleteat some point to free the memory:

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

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

Even better would be to return a smart pointer that will handle the memory management for you:

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

#include <memory>

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

回答by vulkanino

class tile_tree_apple should be defined in a separate .h file.

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

another thing: returning a tile and not a tile reference is not a good idea, unless a tile is a primitive or very "small" type.

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

回答by Luchian Grigore

To do anything other than declare a pointer to an object, you need the full definition.

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

The best solution is to move the implementation in a separate file.

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

If you mustkeep this in a header, move the definition after both declarations:

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

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

Important

重要的

You have memory leaks:

你有内存泄漏:

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

will create an object on the heap, which you can't destroy afterwards, unless you do some ugly hacking. Also, your object will be sliced. Don't do this, return a pointer.

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

回答by Seagull

To perform *new tile_tree_applethe constructor of tile_tree_appleshould be called, but in this place compiler knows nothing about tile_tree_apple, so it can't use the constructor.

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

If you put

如果你把

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

in separate cpp file which has the definition of class tile_tree_apple or includes the header file which has the definition everything will work fine.

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