-3

これは私のコードです:

#include <iostream>
#include <string>

using namespace std;

class C
{
private:
    string str;
    friend void func();
};


void func()
{
        str = "Lala";
        cout << str << endl;

}

int main()
{
    func();
}

これが機能しない理由がわかりません。
私のより大きなプロジェクトでは、クラス外の関数を使用してクラスのプライベート変数にアクセスしたいと考えています。
ここではクラス C を作成し、関数 func(); を作成しました。その友達になるために。しかし、それでも関数内でプライベート変数を使用することはできません。
私が間違っていたことと、これを行うためのより良い方法はありますか?

4

6 に答える 6

3

func()はメンバー関数ではなく、 type のパラメーターを受け取っていませんCどのオブジェクトを操作することになっていますか?

funcのメンバー関数である必要がありますC(この場合、 のインスタンスに対して呼び出しますがC、必須でfriendはありません)、型のパラメーターを受け取る関数C(またはローカルCオブジェクトを作成する関数) のいずれかであり、その上で動作します。 、そのプライベート フィールドにアクセスすることさえできます。

于 2013-06-29T13:36:16.790 に答える
2

問題

コードを少しずつ見てみましょう。

#include <iostream>
#include <string>

using namespace std;

ここで簡単に注意してください: を使用するのは悪い考えusing namespace std;です。

class C
{
private:
    string str;
    friend void func();
};

ここで、クラス C を定義します。このクラスのオブジェクトにはプライベートな文字列が含まれることを宣言し (つまり、クラス メンバーとフレンドのみがアクセスできます)、グローバル関数void func()をフレンドとして宣言します。つまり、許可されます。strクラスCおよびタイプ の任意のオブジェクトのプライベート メンバー (この場合は ) にアクセスしますC。そのパーミッションとは別にfunc、クラスとはまったく関係がないことに注意してくださいC

void func()
{
        str = "Lala";
        cout << str << endl;

}

strここでは、宣言したことのない変数に代入しようとしています。タイプ のプライベート メンバーとオブジェクトにアクセスできること以外 funcに、クラスとの関係はないことに注意してください。ただし、タイプのオブジェクトは見えません。あったとしても、どのオブジェクトから取得するか、またはinについて話していることをコンパイラに伝えるものは何もありません。I'll remember you againは から完全に独立しているため、コードはがフレンドであると宣言しなかった場合と同じように解釈されます。CCCCstrstrCfuncCC

int main()
{
    func();
}

わかりました、ここでは特別なことは何もありませんfunc

修正方法

では、コードを修正するにはどうすればよいでしょうか。まあ、いくつかの可能性があります:

オブジェクトの提供

ローカル オブジェクト

は classのオブジェクトstrのメンバーであるため、クラスのオブジェクトが必要になります。したがって、たとえば次のことができます。C

void func()
{
  C object;
  object.str = "Lala";
  std::cout << object.str << std::endl;
}

ここでは、 でローカル オブジェクトを作成し、そのオブジェクトのメンバーに値をfunc割り当ててから出力します。異なるオブジェクトが異なるメンバーを持っていることを確認するには、たとえば次のように記述できます。 str

void func()
{
  C object1, object2;
  object1.str = "Lala";
  object2.str = "Lele";
  std::cout << object1.str << " -- " << object2.str << "\n";
}

Lala -- Leleこれは、最初のオブジェクトのstrメンバーが value"Lala"を持ち、2 番目のオブジェクトのstrメンバーがvalue を持っているため、出力されます"Lele"

関数の引数

別のオプションは、オブジェクトを引数として渡すことです。

void func(C object)
{
  std::cout << object.str << " -- ";
  object.str = "Lele";
  std::cout << object.str << " -- ";
}

int main()
{
  C main_object;
  main_object.str = "Lala";
  func(main_object);
  std::cout << object.str << std::endl;
}

これは印刷されLala -- Lele -- Lalaます。

ここで何が起こるかというと、メンバーに値が割り当てられmainたオブジェクトが作成されます。を呼び出すと、そのオブジェクトのコピーが作成され、 からアクセスします。これはコピーなので、最初はfunc func str "Lele" main` が示すのと同じ値も含まれています。str"Lala"funcfunc"Lala", whichthen outputs. Then the assignment inchanges themember *of that copy* toand outputs that. The original object is not affected as the output in

ご覧のとおり、複数のオブジェクトが存在する可能性があり、アクセスしたいオブジェクトのstrメンバーを指定することが重要です。

呼び出された関数でオブジェクトを変更するつもりがない場合、コピーを作成するのは時間の無駄です。したがって、それを const への参照として渡すこともできます。

void func(C const& object)
{
  std::cout << object.str << std::endl;
}

int main()
{
  C main_object;
  main_object.str = "Lala";
  func(main_object);
}

引数C const&は、「呼び出し元から渡されたオブジェクトに直接アクセスしたいが、変更しないことを約束する」と述べています。「直接アクセスする」部分は で示され、&「変更しないことを約束します」は で示されますconst。コンパイラーは実際に、あなたが約束を守っていることをチェックし、それを変更しようとしない (つまり、あなたが約束を変更しようとした場合funcobject.str = "Lele"コンパイラーは文句を言うでしょう (コンパイラーにそれについて黙るように指示する方法はありますが、そうすべきです) t do that; just keep your promise). ただし、これはその特定のオブジェクトにのみ適用されることに注意してください; たとえば、次のコードは完全に問題ありません:

void func(C const& object)
{
  C another_object;
  another_object.str = "Lele";
  std::cout << object.str << " -- " << another_object.str << std::endl;
}

int main()
{
  C main_object;
  main_object.str = "Lala";
  func(main_object);
}

Lala -- Lele別のオブジェクトを再度扱っているため、これによりエラーは発生せず、出力されます。

もちろん、渡されたオブジェクトを変更したい場合もあるでしょう。次に、&なしで使用できますconst

void func(C& object)
{
  std::cout << object.str << " -- ";
  object.str = "Lele";
  std::cout << object.str << " -- ";
}

int main()
{
  C main_object;
  main_object.str = "Lala";
  func(main_object);
  std::cout << object.str << std::endl;
}

これは印刷されLala -- Lele -- Leleます。

ここで再び から引数として渡されたオブジェクトに直接アクセスしますがmain、今回は変更しないことを約束せず、実際に変更します。からの出力はmain、実際main_objectに変更されたことを示しています。

変数を静的メンバーにする

ここで、そのタイプのオブジェクトごとに個別のものではなく、に1 つだけ存在することを本当に望む可能性があります。これがあなたが望むものであると絶対に確信しているなら、クラスの静的メンバーを作ることができます:strCstr

class C
{
private:
  static std::string str; // note the keyword "static" here
  friend void func();
};

std::string C::str; // You have to have an extra definition for class static variables!

strこれで、利用可能なオブジェクトがなくてもアクセスできCます。ただし、内部にアクセスしたいことを内部のコンパイラに伝える必要があることに注意してください。funcstrC

void func()
{
  C::str = "Lala";
  std::cout << C::str << std::endl;
}

オブジェクトのメンバーであるのように、オブジェクトの変数にアクセスすることもできます。ただし、これは、さまざまなオブジェクトが独自の を持っているという意味ではないことに注意してstrください。たとえば、変更されたクラス定義では、上記のコードの動作が異なります。

void func()
{
  C object1, object2;
  object1.str = "Lala";
  object2.str = "Lele";
  std::cout << object1.str << " -- " << object2.str << "\n";
}

オブジェクトに依存しない がLele -- Lele1 つしかないため、出力を取得します (この場合の構文は、その点で誤解を招きます。実際には、 「 のに対して定義された 、つまり」を意味します)。strobject1.strstrobject1C

于 2013-06-29T13:58:43.323 に答える
2

str は func() 内で定義されていないため、これは機能しません。C のインスタンスが必要です。

void func()
{
    C foo;
    foo.str = "Lala";
    cout << str << endl;
}

必要に応じて、C インスタンスをパラメーターとして渡すことができます。

void func(C &foo)
{
    foo.str = "Lala";
    cout << str << endl;
}
于 2013-06-29T13:35:34.003 に答える
1
void func(C* object)
{
        object->str = "Lala";
        cout << object->str << endl;

}

はクラスのメンバーではないためfunc、 のように呼び出すことはできませんobject.func()。したがって、関数は、変更したいクラスのオブジェクトを認識しません。そのため、オブジェクト ポインターを関数に明示的に渡す必要があります。参照を使用することもできます。

strまたは、 として宣言することもできますstatic。ただし、静的メンバーは、クラスのすべてのインスタンスが同じ値を共有するようにします。

于 2013-06-29T13:39:46.610 に答える