-2

ソースファイル s.cpp からの構造体があります。

struct s{
unsigned long long a;
s(unsigned long long b){a=b;}
unsigned long long get(){return a;}
};

そしてメインファイルでは、もちろんg ++ main.cpp s.cppの簡単な構文でコンパイルされています

struct s{
s(unsigned long long b);
unsigned long long get();
};

s s1(123456);
//some code
unsigned long long c=s1.get();

これで、未定義の参照を返すようにコンパイルされないことがわかりました。これは残念です。ctor と get() を s.cpp の括弧の外側で定義する必要があります。おそらく必要ないというg ++フラグがあるのだろうか。しかし、主な問題は、s1.get() は安全なのか、それとも未定義の動作なのかということです。

編集

ご回答ありがとうございますが、私はまだメカニズムをよく理解していません。この場合、s.cpp では次のようになります。

struct teste{
    int a=0;
    teste(int b);
    int g();
};
teste::teste(int b){a+=b;}
int teste::g(){ return a;}

そして主に:

struct teste{
    int c=1;
    teste(int b);
    int g();
};

teste ato(8);
printf("\n%d",ato.g());

メモリの割り当てを考えると、実際のパフォーマンスでは 8 ではなく 9 を返すべきではありませんか? c を a に変更して正確に 1 に変更しても、常に s.cpp から a とその初期値を探しているようです。メソッド以外のものを main に宣言するのは余計なことだと思います。

4

5 に答える 5

2

宣言と定義の奇妙な組み合わせがあります。

まず、クラス宣言 (ヘッダー ファイルに入れ、 に含めるmain必要があります) は次のようになります。

struct s
{
  unsigned long long a;
  s(unsigned long long b);
  unsigned long long get();
};

次に、実装は次のようになります

s::s(unsigned long long b) a(b) {}

unsigned long long  s::get() { return a; }
于 2013-05-16T17:02:40.713 に答える
1

私がそれを正しく理解している場合、問題は、宣言と定義を1つのファイルに入れ、別の宣言を別の翻訳単位に入れることは、ヘッダーファイルに宣言を入れることと比較して合法かどうかです。

同じ型のすべての宣言がすべての翻訳単位*でまったく同じである場合に限り、それは有効です。ただし、宣言の 1 つを変更したり、その他の変更が正確な定義に影響を与えたりすると、ODR が壊れて未定義の動作が発生するため、エラーが発生しやすくなります。

* : 宣言がテキスト的に同じである必要があるだけでなく、各シンボルのルックアップが同じエンティティを生成する必要があり、基本的にそれらは正確に 1 つだけのものを参照する必要があります。

于 2013-05-16T17:21:03.363 に答える
0

ここでの問題は、 のメンバー関数がs.cpp でs暗黙的に定義されていることです。inlineこれにより、これらのメンバー関数が s.cpp の翻訳単位でのみ定義されるように制限されます。main.cpp では、コンパイラは宣言のみを確認します。したがって、リンカーエラー。(誰かが確認できれば、これは「内部リンケージ」などと呼ばれると思いますか?)

前述のように、関数の定義を外部sに移動すると、コンパイラ エラーが解決されます。その理由は、定義がもはやinline. したがって、定義を main.cpp にリンクして使用できるようになりました。したがって、新しいコードは明確に定義された C++ です。

関数に関する問題inlineは、それらが使用されるすべての翻訳単位で定義する必要があるということです。このため、inline関数は通常ヘッダー ファイルに配置されるため、単純なファイルで#include十分です。

于 2013-05-16T17:08:00.727 に答える
0

おそらく同じ名前空間で、同じ名前の 2 つの異なる構造体を混在させているため、問題が発生する可能性があります。

s.cpp では (コードを少し変更して理解しやすくしました):

struct s{ //I'll refer to this struct as S1 below
    int _a;
    s(int a) : _a(a) {}
    int get() {return _a;}
};

main.cpp で

// you added this struct declaration because otherwise it desn't compile
// (providing there is no silly #include "s.cpp")
// But it actually declares ANOTHER struct called s as well
struct s{ // I will refer to this struct as S2 below
    s(int a);
    int get();
};

s my_s(123);
//some code
int c = my_s.get(); // the compiler checks that S2 contains a get function: OK

ここで、リンカがs同じ名前空間で 2 つのシンボルを認識し、デバッグが非常に面倒な問題が発生します。値を取り戻すことができ123、すべて正常に動作しているように見えますが、リリースでコンパイルします (または、コンパイラを変更するか、プラットフォームを変更するか、マシンを再起動するか、コードの動作を変更すべきではないと思われるその他のことを行います)。 ) そして、それはもう機能しません...

そのような問題を回避するために、構造体を使用する場合は、それを使用する行の前に宣言する必要があります。shで宣言し、s.cppで定義します(.cppファイルでやろうとしたことだと思いますが、すべての関数を個別に定義する必要があります):

// s.h
struct s{
    unsigned long long a;

    s(unsigned long long b);
    unsigned long long get();
};

// s.cpp
s::s(unsigned long long b) : a(b) {}

unsigned long long s::get() { return a; }

または、.h ファイル内のすべてをインライン化し、main.cpp に含めます。

于 2013-05-16T17:08:20.307 に答える