C ++没有命名类型错误

时间:2012-06-09 07:10:14

标签: c++ makefile

我似乎无法确定这个问题,所以我想我会问这里。我知道为什么会出现这个错误,但这次我似乎无法弄明白。可能是一些我不知道或遗失的简单事。

g++  -c -I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT src/Render.cpp -L/usr/lib/i386-linux-gnu -lSDL -lSDL_image
src/Render.cpp:8:1: error: ‘Render’ does not name a type
src/Render.cpp:13:1: error: ‘Render’ does not name a type
src/Render.cpp:18:14: error: ‘Render’ has not been declared
src/Render.cpp:31:6: error: ‘Render’ has not been declared
make: *** [Render.o] Error 1

这是我的core.cpp,Makefile和Render.h

Render.cpp

#ifndef _Render_h
#define _Render_h
#include <iostream>
#include "SDL/SDL_image.h"

using namespace std;

Render::Render()
{

}

Render::~Render()
{

}

SDL_Surface* Render::loadImg(string filename)
{
    SDL_Surface* temp = NULL;
    SDL_Surface* optimized = NULL;

    if((temp = IMG_Load(filename.c_str())) != NULL)
    {
        optimized = SDL_DisplayFormat(temp);
        SDL_FreeSurface(temp);
    }
    return optimized;
}

void Render::applySurface(int x, int y, SDL_Surface* source,
        SDL_Surface* destination)
{
    SDL_Rect offset;
    offset.x = x;
    offset.y = y;
    SDL_BlitSurface(source, NULL, destination, &offset);    
}

#endif

core.cpp

#include <iostream>
#include "SDL/SDL.h"
#include "Render.h"

using namespace std;

int main(int argc, char* args[])
{
    string imgGoku = "src/imgs/Goku.bmp";
    string imgVegeta = "src/imgs/Vegeta.png";
    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;
    const int SCREEN_BPP = 32;
    SDL_Surface *message = NULL;
    SDL_Surface *background = NULL;
    SDL_Surface *screen = NULL;
    Render rnd;

    if(SDL_Init(SDL_INIT_EVERYTHING) == -1)
    {
        return 1;
    }

    screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT,
            SCREEN_BPP, SDL_SWSURFACE);
    if(screen == NULL)
    {
        return 1;
    }

    SDL_WM_SetCaption("Hello World", NULL);
    rnd.applySurface(10,10,rnd.loadImg(imgGoku),screen);
    if(SDL_Flip(screen) == -1)
    {
        return 1;
    }

    SDL_Delay(2000);
    SDL_FreeSurface(message);
    SDL_FreeSurface(background);
    SDL_Quit();
    return 0;
}

Render.h

#include "SDL/SDL.h"

using namespace std;

class Render{
    public:
        Render();
        ~Render();
        SDL_Surface* loadImg(string filename);
        void applySurface(int x, int y, 
                SDL_Surface* source, 
                SDL_Surface* destination);
};

生成文件

#Game Make file
TARGET = game.exe
OBJS = core.o \
       Render.o \

SDL_CFLAGS := $(shell sdl-config --cflags)
SDL_LDFLAGS := $(shell sdl-config --libs) -lSDL_image
CFLAGS = -Wall
LIBS =
LDFLAGS = 

$(TARGET): $(OBJS)
       g++ $(CFLAGS) $(SDL_CFLAGS) -o $@  $(LDFLAGS) $(OBJS) $(SDL_LDFLAGS) $(LIBS)
%.o: src/%.cpp src/Render.h
       g++  -c $(SDL_CFLAGS) $< $(SDL_LDFLAGS)

.PHONY: clean
clean:
    rm -f $(TARGET) $(OBJS)

2 个答案:

答案 0 :(得分:3)

您需要在Render.cpp顶部包含Render.h

答案 1 :(得分:3)

  

烨。我认为这就是#ifndef和#define的作用,但我想我理解它们或使用它们是错误的。

你误解了他们你错误地使用了它们。

虽然向Render.cpp文件添加#include "Render.h"指令会修复您的即时编译问题,但它并不能解决误解和误用的双重问题。您应该对代码进行其他两个修复。我将总结你应该做出的更正,然后说明为什么要这样做。

问题#1:您需要将#ifndef _Render_h / #define _Render_h对和结束#endif从源文件移动到标题。

问题#2:从预处理器符号_Render_h中删除前导下划线。

#include guards
查看几乎所有系统头文件,您会看到它们遵循非常标准的布局。该文件以描述该文件的标题注释开头。紧接着这是一对#ifndef _SOME_NAME_H_#define _SOME_NAME_H_形式的行。文件正文如下,文件中的最后一项是结束#endif。该#ifndef / #define对称为#include后卫。关闭#endif总是(好吧,几乎总是;其中一些系统标题违反了标准布局)。

这样做是为了防止多次包含相同的标头。假设您有头文件foo.h,bar.h和baz.h.假设foo.h和bar.h都使用baz.h中定义的功能。这些标题中的每一个都应该具有#include "baz.h"指令,最好在顶部附近。现在假设你的main.cpp #include是foo.h和bar.h.如果文件baz.h没有#include防护,它将在main.cpp中包含两次。你的main.cpp很可能无法编译。

这个多重包含问题的解决方案是将#include保护放在文件baz.h中。现在main.cpp中的#include "foo.h"会将baz.h的主体粘贴到您的代码中,但#include "bar.h"不会,因为baz.h中的#include后卫会生成预处理器跳过baz.h的主体。

最好在每个头文件中放一个#include守卫。

#pragma一次
#include守卫的概念有几个问题。

  • 名称必须指定两次,一次在#ifndef指令中,另一次在#define指令中。这对于墨菲法则来说是一个巨大的机会,可以让它变得丑陋。程序员可以并且确实错误地输入了这些名称中的一个。
  • 最后#endif是另一个潜在的问题来源。一些维护程序员(维护程序员是开发程序员存在的祸根)将会看到在关闭#endif之后添加代码将对他的烦恼问题做出快速而肮脏的修复。维护程序员总是选择最快,最脏的解决方案。做完了。
  • 名称必须是唯一的。假设您只是在一个大项目中工作的人之一,并假设您和其他人都有一个名为Render.h的文件。这两个文件位于两个不同的目录中,因此具有相同名称的两个文件没有问题。如果两个文件都使用预处理器符号#include进行Render_h保护,则会出现一个巨大的问题。

这些问题有一个很好的解决方案,即#pragma once指令。如果这个pragma工作正常,它确实与#include后卫打算做的完全相同,但更好。只有一行而不是三行,并且没有预处理器名称。问题是“如果它有效”。这是一个pragma,所以并非所有的编译器都支持它,而且一些支持它的人不能正确使用它。

由于#include的可移植性问题,我倾向于使用#pragma once警卫。其他人使用#pragma once因为可移植性问题不适用于他们的项目。还有一些人使用这两种机制。

引导下划线
如果你查看一个系统头文件,你会看到它充满了带有前导下划线的名字。这可能会给人留下这样的印象:使用前导下划线是正确的做法。毕竟,谁比编译器供应商更了解语言?

编译器供应商使用前导下划线的原因是为了避免与代码冲突。一个好的编译器供应商正好使用前导下划线,因为如果你不在任何名字中使用前导下划线,这样做会使他们的名字不与你的名字发生冲突。永远不要在类的名称,全局变量,自由函数或预处理器符号中使用前导下划线。前导下划线保留供编译器使用。