1

これは、 Google の C++ コーディング ガイドラインからの抜粋です。

定義にアクセスせずにヘッダーファイルでクラス Foo を使用するにはどうすればよいですか?

  • Foo* または Foo& 型のデータ メンバーを宣言できます。
  • Foo 型の引数および/または戻り値を持つ関数を宣言できます (定義はできません)。(1 つの例外は、引数 Foo または const Foo& に非明示的な 1 つの引数のコンストラクターがある場合です。この場合、自動型変換をサポートするには完全な定義が必要です。)
  • Foo 型の静的データ メンバーを宣言できます。これは、静的データ メンバーがクラス定義の外で定義されているためです。

私が気になるのは、2 番目の箇条書きの例外です。これはなぜですか?自動型変換をサポートしたいのに、なぜ完全な定義が必要なのですか?

私の推測では、暗黙的な変換で一時オブジェクトが作成されるため、コンパイラーは宛先タイプの完全な定義を必要としていると思います。私は正しく推測していますか?それ以上のことはありますか?

編集:

私が見ているように、ガイドラインの例外は次のような状況に対処しています:

class A
{
    public:
        A( int );
};

class B
{
    public:
        B( A const &a );
};

int main()
{
    B b(2);
}

ここでは、ユーザー定義の暗黙的な変換 (int から A へ) が 1 つだけあり、const & を受け入れるコンストラクターを呼び出します。この例外で意味のある唯一のことは、たとえば int から A への直接変換をサポートし、次に A const & を受け入れるコンストラクターを介して B への直接変換をサポートすることです。これにより、A クラスが存在するヘッダー ファイルを明示的に含める必要なく、クライアント コードがこの変換チェーンを使用できるようになります。宣言した。

4

3 に答える 3

2

C ++言語は、ヘッダーファイルと他のファイルのコードを区別しません。ヘッダーがファイルである必要はありません。したがって、純粋に技術的にはこの質問は無意味ですが、実際には、単一定義規則に違反しないように、ヘッダーファイルで行うことを制限します。自分自身を制限することなく、ユーザーは1つの翻訳単位にのみヘッダーファイルを含めるように注意する必要があります。適切な制限があれば、ヘッダーファイルを複数の翻訳単位に自由にインクルードできます。

不完全なタイプとは、サイズが不明sizeofで使用できないタイプのことです。

クラス定義がわからない場合、クラスFooは必然的に不完全です。

これは、サイズを知る必要があることを行うことができないことを意味します。また、不完全性とはメンバーが不明であることを意味するため(サイズがわかっていれば、メンバーは必然的にわかります)、通常、メンバーを呼び出すことはできません。例外:のようにデストラクタを呼び出すことができ、コンパイラはそれを受け入れる必要がありますが、クラスに重要なデストラクタがあるdelete pFoo場合は未定義動作です。Foo

ただし、Googleガイドラインに記載されている例外は無意味です。

編集:私は、物事が詳細に説明されていると、SOの人々がそれを好むことを発見したので、ガイドラインが無意味である理由についての議論を追加します。

ガイドラインでは、「宣言する(ただし定義することはできない)」ことができますが、「1つの例外は、引数Fooまたはconst Foo&に非明示的な1つの引数のコンストラクターがある場合です」と記載されています。

宣言はコンストラクターとは何の関係もありません。コンストラクターは、試してみるだけで確認できます。

#include <iostream>

struct Foo;

Foo bar( Foo const& );  // Declaration of function bar, works fine.

struct Foo
{
    int x_;
    Foo( int x ): x_( x ) {}       // Converting constructor.
};

int main()
{
    std::cout << bar( 42 ).x_ << std::endl;
}

Foo bar( Foo const& foo ) { return foo; }

結論として、ここでも、Googleガイドラインの例外は無意味です。

乾杯&hth。、

于 2010-12-16T17:12:26.517 に答える
0

2 番目の点の例外が正しいかどうかはわかりません。暗黙的な変換は、関数が宣言されたときではなく、関数が呼び出されたときにのみ認識される必要があるため、宣言されているC間は不完全ですが、次のように機能fします。

#include <iostream>
class C;
void f(C);
struct C { C(int i) { std::cout << "C(" << i << ")" << std::endl; } };
void f(C c) { std::cout << "f(C)" << std::endl; }
int main() { f(2); }
于 2010-12-16T16:56:08.470 に答える
0

宣言だけをfoo.h知っているとしますFoo

//foo.h

class Foo;
void f(const Foo &); // It is possible to use the reference.

完全な定義はfoo.cpp

// foo.cpp

class CanBeConvertedToFoo;
class Foo
{
   Foo (const CanBeConvertedToFoo & x); // implicit constructor
}

class CanBeConvertedToFoo暗黙的に Foo に変換可能です。しかし、それは不明ですsome.cpp

// some.cpp

#include "foo.h"
void g(const CanBeConvertedToFoo & x) {
   f(x); // Is it known about implicit conversion ?
}
于 2010-12-16T16:50:42.527 に答える