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
C++ class forward 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 B
that uses objects of class A
.
假设您要定义一个B
使用 class 对象的新类A
。
B
only uses references or pointers toA
. 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 ; } ;
B
derives fromA
orB
explicitely (or implicitely) uses objects of classA
. You then need to include<A.h>
#include <A.h> class B : public A { }; class C { private: A fA ; public: void mymethod(A par) ; }
B
仅使用指向A
. 使用前向声明,则不需要包含<A.h>
. 这将反过来加快编译速度。class A ; class B { private: A* fPtrA ; public: void mymethod(const& A) const ; } ;
B
派生自A
或B
显式(或隐式)使用类的对象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 T
to compile, T
must be a complete type. In your case, when you say new tile_tree_apple
inside the definition of tile_tree::tick
, tile_tree_apple
is 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::tick
,tile_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_tree
into a tile
, which discards the information that makes a tile_tree
different 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 delete
at 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_apple
the constructor of tile_tree_apple
should 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 文件中,一切正常。