3

これまで何度もインクルードガードを使用してきましたが、それらがどのように、またはなぜ機能するのかを本当に理解していませんでした。

以下が機能しないのはなぜですか?

#ifndef CAMERA_CLASS_HPP
#define CAMERA_CLASS_HPP


class camera_class
{
....
};

camera_class glcam = camera_class();


#endif // CAMERA_CLASS_HPP

エラーは次のとおりです: (おそらく、この質問のタイトルから推測できます!)

-------------- Build: Debug in System ---------------

Linking console executable: bin/Debug/System
/usr/bin/ld: error: obj/Debug/main.o: multiple definition of 'glcam'
/usr/bin/ld: obj/Debug/camera_class.o: previous definition here
/usr/bin/ld: error: obj/Debug/main.glfunc.o: multiple definition of 'glcam'
/usr/bin/ld: obj/Debug/camera_class.o: previous definition here
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)
0 errors, 0 warnings

また、ヘッダーガードが機能する理由を誰か説明してもらえますか?

4

6 に答える 6

8

ヘッダーガードは、単一の翻訳ユニットに複数が含まれるのを防ぎます。ヘッダーは、複数の翻訳単位に含めることができます(現在も含まれています)。

// a.cpp:
#include "camera.hpp"

// b.cpp
#include "camera.hpp"

これにより、とが生成さa.objb.obj、それぞれに。の定義が含まれglcamます。一緒にリンクして最終的なバイナリを生成すると、複数定義エラーが発生します。

ヘッダーで宣言 し、ファイルで1回だけ定義する必要があります。glcam.cpp

// camera.hpp
...

extern camera_class glcam;

// camera.cpp
#include "camera.hpp"

camera_class glcam;
于 2012-09-07T14:48:20.333 に答える
4

根本原因:ヘッダー ガードは、同じ翻訳単位
に同じヘッダーが複数回含まれないようにしますが、異なる翻訳単位にまたがることはできません。同じヘッダー ファイルを複数の翻訳単位に含めると、ヘッダーを含めるすべての翻訳単位で のコピーが実際に作成されます。 C++ 標準では、各シンボルを1 回だけ定義できることが義務付けられているため( One Definition Rule )、リンカーはエラーを発行します。
glcam

解決策:ヘッダー ファイルに
作成しないでください。glcam代わりに、一度だけ定義されるような方法で作成する必要があります。これを行う正しい方法は、キーワードを使用することexternです。

于 2012-09-07T14:47:37.503 に答える
3

It looks like you want to create a single glcam object that can be used in multiple places. I would do that by exposing a free function to return a static instance. This is similar to using extern, but I find it to be a little more explicit in its intent.

#ifndef CAMERA_CLASS_HPP
#define CAMERA_CLASS_HPP


class camera_class
{
....
};

camera_class& get_camera();


#endif // CAMERA_CLASS_HPP

// in the CPP

camera_class& get_camera()
{
   static camera_class the_camera;
   return the_camera;
}

This gives you the ability to use a single camera_class instance without relying on extern, but at the same time doesn't force you to use it as a singleton, as other areas of the code are free to create their own private instances as well.

This could be implemented as it is (a free-function) or as a static member function of the camera_class. I chose the former, based on some excellent advice from Scott Meyers:

If you're writing a function that can be implemented as either a member or as a non-friend non-member, you should prefer to implement it as a non-member function.

Source: http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197

于 2012-09-07T14:52:15.210 に答える
2

このファイルを複数のファイルから含めているため、単一定義規則に違反しています。

プログラム全体で、オブジェクトまたは非インライン関数に複数の定義を含めることはできません

glcam定義をヘッダーファイルではなくソースファイルに配置するか、代わりにとして宣言して、externソースファイルに定義を提供する必要があります。

于 2012-09-07T14:48:56.693 に答える
1

インクルードガードは、ヘッダー内のテキストの複数のインスタンスが1つのコンパイルユニットに表示されないようにします(つまり、作成している単一の.cppが.oに組み込まれます)。

そのテキストの複数のインスタンスが複数のコンパイル単位に表示されるのを防ぐことはできません。

したがって、リンク時に、このヘッダーを含む各コンパイルユニットには

 camera_class glcam = camera_class();

シンボルとして。C ++は、「glcam」を参照するときに、どの単一のグローバル定義を意味するかを判断できません。main.oからのものですか、それともcamera_class.oからのものですか?

于 2012-09-07T14:48:42.917 に答える
0

これは問題なく機能しており、各ソースファイルで取得できる定義は1つだけです。

問題は、複数のソースファイルがあり、リンカが複数の定義を見つけていることです。

ヘッダーファイルに次のように配置する必要があります。

extern camera_class glcam;

そして、たった1つのソースファイルに、以前持っていたものをヘッダーに入れます。

camera_class glcam = camera_class();

この時点で、初期化順序の問題に注意する必要があります。glcam静的オブジェクトから使用しようとしないでください。

于 2012-09-07T14:49:41.780 に答える