当我尝试编译此代码时,我得到:
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;};
};
我真的不知道该怎么做,我搜索了解决方案,但我找不到任何与我的问题相似的东西......实际上,我有更多的课程与父母“瓷砖”,之前还可以...... 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"
它只在基类中,其他一切都没问题... 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() {};
};
答案 0 :(得分:17)
尽可能使用前瞻声明。
假设您要定义一个使用类B
对象的新类A
。
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) ;
}
答案 1 :(得分: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() {...}
当您以这种方式编写代码时,这些方法中对A和B的所有引用都保证引用完整类型,因为没有更多的前向引用!
答案 2 :(得分:8)
前向声明是“不完整类型”,你可以用这种类型做的唯一事情就是实例化一个指针,或者在函数中引用它声明(即函数原型中的参数或返回类型)。在代码的第52行中,您尝试实例化对象。
此时编译器不知道对象的大小及其构造函数,因此无法实例化对象。
答案 3 :(得分: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;
}
...
和原始问题一样悲伤。 只有通过将paulzSprite的定义移动到之后 spriteFrame才能解决。难道编译器不应该比这更聪明(VC ++,VS 11 Beta)吗?
顺便说一句,我完全同意克利福德上面的评论&#34;指针不会导致内存泄漏,编码不良会导致内存泄漏&#34;。恕我直言,许多其他新的&#34;智能编码&#34;功能,不应该成为理解你实际要求计算机做什么的替代品。
答案 4 :(得分:4)
问题是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_tree
与tile
不同的信息;这称为切片。
您想要的是返回指向新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>();
}
答案 5 :(得分:3)
类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;};
};
另一件事:除非瓷砖是原始类型或非常“小”类型,否则返回瓷砖而不是瓷砖参考不是一个好主意。
答案 6 :(得分:0)
除了声明指向对象的指针之外,还需要完整的定义。
最佳解决方案是将实施移到单独的文件中。
如果必须将其保留在标题中,请在两个声明后移动定义:
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;};
将在堆上创建一个对象,除非你做了一些丑陋的黑客行为,否则你不能在之后销毁它。此外,您的对象将被切片。 不要这样做,返回指针。
答案 7 :(得分:0)
要执行*new tile_tree_apple
,应该调用tile_tree_apple
的构造函数,但是在这个位置编译器对tile_tree_apple
一无所知,所以它不能使用构造函数。
如果你把
tile tile_tree::tick() {if (rand()%20==0) return *new tile_tree_apple;};
在单独的cpp文件中,该文件具有类tile_tree_apple的定义或包含具有定义的头文件,一切都将正常工作。
答案 8 :(得分:-2)
我是CPP菜鸟,但是你不必在前方声明中指定继承吗?
class tile_tree_apple : public tile;