0

この問題を特定できないようですので、ここで質問しようと思いました。このエラーが通常表示される理由はわかっていますが、今回は理解できないようです。おそらく、私が知らない、または欠けている単純なものです。

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

コア.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)
4

2 に答える 2

3

Render.cppの先頭にRender.hを含める必要があります

于 2012-06-09T07:16:54.463 に答える
3

うん。それが #ifndef と #define の機能だと思っていたのですが、理解できたか、使い方が間違っていたようです。

あなたはそれらを誤解し、間違って使用しました。

#include "Render.h"Render.cpp ファイルにディレクティブを追加すると、すぐにコンパイルの問題が解決されますが、誤解と誤用という 2 つの問題は解決されません。コードに加えるべき修正が他に 2 つあります。修正すべき点を要約し、その理由を説明します。

#ifndef _Render_h問題 #1: /#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"には、できれば上部近くにディレクティブが必要です。ここで、main.cpp#includeが foo.h と bar.h の両方であるとします。ファイル baz.h にガードがない場合、#includemain.cpp に 2 回含まれます。main.cpp はおそらくコンパイルされません。

この複数のインクルードの問題に対する解決策は#include、ファイル baz.h にガードを配置することです。これ#include "foo.h"で、main.cpp の は baz.h の本体をコードに貼り付けますが、baz.h のガードによってプリプロセッサが baz.h の本体をスキップする#include "bar.h"ため、貼り付けられません。#include

#includeヘッダー ファイルのすべてにガードを配置することをお勧めします。

#pragma onceガード
の概念にはいくつかの問題があります。#include

  • 名前は、ディレクティブで 1 回、#ifndefディレクティブで 2 回、2 回指定する必要があります#define。これは、マーフィーの法則が醜い頭をもたげる絶好の機会です。プログラマーは、これらの名前のいずれかをタイプミスする可能性があり、実際にタイプミスを犯します。
  • 最後に、問題の#endif別の潜在的な原因があります。一部のメンテナンス プログラマー (メンテナンス プログラマーは開発プログラマーの存在の悩みの種です) は、クロージング#endifにコードを追加すると、彼の厄介な問題が迅速かつ汚い修正になることに気付くでしょう。メンテナンス プログラマーは常に、可能な限り迅速で最も汚れたソリューションを選択します。これで完了です。
  • 名前は一意である必要があります。あなたが大きなプロジェクトに取り組んでいる多くの人の 1 人に過ぎず、あなたと他の誰かが Render.h という名前のファイルを持っているとします。2 つのファイルは 2 つの異なるディレクトリにあるため、2 つのファイルが同じ名前であっても問題ありません。#include両方のファイルにプリプロセッサ シンボルを使用したガードがある場合、大きな問題が発生しますRender_h

これらの問題には、#pragma onceディレクティブという優れた解決策があります。このプラグマが機能する場合、#includeガードが意図したとおりに動作しますが、より優れています。3 行ではなく 1 行しかなく、プリプロセッサ名もありません。問題は、「それが機能するかどうか」です。これはプラグマであるため、すべてのコンパイラがサポートしているわけではありません。

#includeの移植性の問題から、ガードを使用する傾向があります#pragma once。他の人は#pragma once、移植性の問題がプロジェクトに当てはまらないために使用します。さらに、両方のメカニズムを使用するものもあります。

先頭のアンダースコア
システム ヘッダー ファイルを見ると、先頭にアンダースコアが付いた名前がぎっしり詰まっていることがわかります。これは、先頭にアンダースコアを使用することが正しいことであるという印象を与える可能性があります。結局のところ、コンパイラ ベンダーよりも言語をよく知っているのは誰でしょうか?

コンパイラ ベンダーが先頭のアンダースコアを使用する理由は、コードとの衝突を避けるためです。優れたコンパイラ ベンダーは、名前の先頭にアンダースコアを使用しない場合に、先頭にアンダースコアを使用することで名前が競合しないようにするため、先頭にアンダースコアを使用します。クラス、グローバル変数、フリー関数、またはプリプロセッサ シンボルの名前の先頭にアンダースコアを使用しないでください。先頭のアンダースコアは、コンパイラが使用するために予約されています。

于 2012-06-09T10:11:04.160 に答える