C++ 不命名类型错误

C++ Does not name a type error

本文关键字:类型 错误 C++      更新时间:2023-10-16

我似乎无法指出这个问题,所以我想我会在这里问。我知道为什么通常会出现此错误,但这次我似乎无法弄清楚。可能是我不知道或缺少的简单东西。

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

这是我的核心.cpp,Makefile和Render.h

渲染.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

核心.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;
}

渲染.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)
您需要在 Render

的顶部包含 Render.h.cpp

是的。我以为这就是 #ifndef 和 #define 所做的,但我想我理解它们或错误地使用它们。

误解了它们你用错了它们。

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

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

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

#include 卫士
查看几乎所有的系统头文件,您会发现它们遵循非常标准的布局。该文件以描述文件的标题注释开头。紧随其后的是一对形式为 #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" 指令,最好靠近顶部。现在假设你的主.cpp #include s foo.h 和 bar.h。如果文件 baz.h 没有#include保护,它将包含在您的主.cpp中两次。您的主.cpp很可能不会编译。

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

最好

在每个头文件中放置一个#include防护。

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

  • 必须指定两次名称,一次在 #ifndef 指令中,另一次在 #define 指令中。这是墨菲定律养育丑陋头颅的巨大机会。程序员可以并且确实错误地键入了这些名称中的一个或另一个。
  • 最后的#endif是另一个潜在的问题来源。一些维护程序员(维护程序员是开发程序员存在的祸根)会看到,在关闭#endif之后添加代码将快速而肮脏地解决他棘手的问题。维护程序员总是选择最快、最脏的解决方案。就这样完成了。
  • 名称必须是唯一的。假设您只是从事大型项目的众多人员之一,并且假设您和其他人都有一个名为 Render.h 的文件。这两个文件位于两个不同的目录中,因此两个文件具有相同的名称没有问题。如果两个文件都有使用预处理器符号Render_h#include保护,则会出现一个巨大的问题。

这些问题有一个很好的解决方案,即#pragma once指令。这种编译指示,如果它有效,完全符合#include守卫的意图,但更好。只有一行而不是三行,并且没有预处理器名称。问题是"如果它有效"。这是一个编译指示,所以并非所有编译器都支持它,一些支持它的编译器做得不正确。

我倾向于使用#include防护装置,因为#pragma once的便携性问题。其他人使用#pragma once因为可移植性问题不适用于他们的项目。还有一些人同时使用这两种机制。

前导下划线
如果您查看系统头文件,您会发现它充满了带有前导下划线的名称。这可能会给人一种印象,即使用前导下划线是正确的做法。毕竟,谁比编译器供应商更了解该语言?

编译器供应商使用前导下划线的原因是避免与代码发生冲突。一个好的编译器供应商之所以使用前导下划线,正是因为如果您不在任何名称中使用前导下划线,这样做可以防止其名称与您的名称发生冲突。切勿在类、全局变量、自由函数或预处理器符号的名称中使用前导下划线。前导下划线保留供编译器使用。