あるクラスで別のクラスをfriendとするとそのクラスの全メンバにアクセスできますが、
特定のメンバだけをfriendにする事はできるのでしょうか?
例えば、
#include <iostream>
using namespace std;
class A {
friend class B;
static void fa() { cout << A::fa() << endl; }
static void fb() { cout << A::fb() << endl; }
public:
};
class B {
public:
void Execute1() { A::fa(); }
void Execute2() { A::fb(); }
};
int main()
{
B ob;
ob.Execute1(); // OK
ob.Execute2(); // Errorにしたい
return 0;
}
上のコードで、当然class Bからclass Aの全メンバにアクセスできますが、
A::fa()はアクセスできて、A::fb()はアクセスできないようにしたい場合には
どうすればいいのでしょうか?
できなかったと思う。
素早い回答、ありがとうございます。
できないのですか。
ちょっと残念ですが、グローバル関数を介すればそれっぽい事ができますね。
例えば、
#include <iostream>
using namespace std;
class A {
friend void Access();
static void fa() { cout << A::fa() << endl; }
static void fb() { cout << A::fb() << endl; }
public:
};
class B {
public:
void Execute() { Access(); }
};
void Access() { A::fa(); }
int main()
{
B ob;
ob.Execute();
return 0;
}
こんな感じに。
今気がついたんですけどね。
その方法では、Access()はどこからも見えるので、
fa()だけpublicなのと、何も変わっていませんよ。
確かに。
まあ、名前空間に封じて対処するしかないのでしょうね。
あくまで、それっぽい事ですから。
> まあ、名前空間に封じて対処するしかないのでしょうね。
え?
こんなのは?
class SuperA {
friend class B;
static void fa() { cout << A::fa() << endl; }
};
class A : public SuperA {
static void fb() { cout << A::fb() << endl; }
};
class B
{
public:
void Execute1() { A::fa(); } // OK
void Execute2() { A::fb(); } // ERROR
};
なるほど、公開したいヤツを super に追い出す、か。
目的は達せられるけど、superA::fa()の実装が Aのメンバを必要としたら…
ってことがありうるので、適用できるかはビミョーなところ。
おお、なるほど!!
まさにこれをやりたかったのです。
friendって継承されないんですね、忘れてました。
皆さん、ありがとうございました。
> superA::fa()の実装が Aのメンバを必要としたら…
このようなワケの分からんことに...
template < typename Sub >
class SuperA
{
friend class B;
static void fa()
{
cout << A::fa() << endl;
Sub::fb();
}
};
class A : public SuperA< A >
{
friend class SuperA< A >;
static void fb() { cout << A::fb() << endl; }
};
うーむ……小さな目的のために失うものの方が大きい気もするぞ。
同感です.あくまでも頭の体操ということで.
使ったことはないけど,ATLがこんな仕組み(ウィンドウの基本クラスがテンプレートに
なっていて,派生クラスを基本クラスのテンプレート引数に渡す)を使っていたような
気がします.
アドバイスありがとうございます。
なぜこうしたくなったかといいますと・・・
AというクラスはBからしか生成できない、よってAのコンストラクタはprivateです。
そして生成関数 static A*A::Create() という関数を作りますが、これを呼ぶ事が
できるのはBというクラスの B::CreateA() という関数のみしにたい。
だけどAとBは継承関係にはありません。
そしてBからはAのprivateな関数にはアクセス不可能にしたい。(もちろんCreate()以外)
・・・といった状況だったのです。
始めからこう質問すれば良かったですね、説明不足で申し訳ないです。
で、結局A::Create()をpublicにしてB::CreateA()というAの生成関数以外からは
A::Create()を呼ばないように注意するのが一番だという気がします。
もし何かアドバイスがありましたらよろしくお願いします。(解決押しちゃったけど)
ネストかな...
#include <iostream>
class B
{
class A
{
A(){ std::cout << A::constructor << std::endl; }
void f(){ std::cout << A::f() << std::endl; }
public:
static A* create(){ return new A; }
~A(){ std::cout << A::destructor << std::endl; }
void g(){ std::cout << A::g() << std::endl; }
};
public:
void create_a()
{
A* p = A::create();
p->f(); // error
p->g(); // ok
delete p;
}
};
int main()
{
B b;
b.create_a();
B::A* p = B::A::create(); // error
delete p;
}
おお、ネストですか。(やった事なかったです・・・)
ですが、それですとAのstaticな公開メンバにアクセス出来ませんよね?
Bにそれへのインターフェースを付ければいいのかな。
なるほど、参考になりました。
何回もありがとうございます。
これで本当の解決です!!
・・・早く初心者の域を脱したいです。