アクセス権限の意味
アクセス指定子をつけると設定できる
private
該当する関数または変数には,それらが実装されたクラス(のメソッド)のみアクセスできる
protected
該当する関数または変数には,それらが実装されたクラス(のメソッド)とそのクラスから派生したクラス(のメソッド)のみアクセスできる
public
制限はない,オブジェクトを無から生成して渡すためにpublic
の関数を経由する必要がある
アクセス権限の規制
継承時にアクセス指定子をつけると継承元の関数または変数のアクセス権限にリミットがかかる
隠蔽する方向にのみ動作する
private
public
とprotected
がprivate
になる
class A{
private:
int x; // can't acccess from B
protected:
int y;
public:
int z;
}
class B:private A{
// y -> private
// z -> private
}
protected
public
がprotected
になる
class A{
private:
int x; // can't acccess from B
protected:
int y;
public:
int z;
}
class B:protected A{
// y -> protected
// z -> protected
}
public
制限はない
class A{
private:
int x; // can't acccess from B
protected:
int y;
public:
int z;
}
class B:private A{
// y -> protected
// z -> public
}
アクセス権限の変更
using
と::
でスコープをつけながらエイリアスを作成する際,アクセス指定子を先頭につければ個別に上書きできる
昇格
protected
からpublic
にする
class A{
protected:
int x;
}
class B:public A{
public using A::x;
// reachable A.x from public, protected, private
}
使い道
特に思いつかないし,こんなものが必要になるような場面に遭遇したら,ひとまず設計を修正した方が良い気がしています
一括で昇格させる方法
これがどうやら存在しないらしい.やるならば全てに一対一でpublic using Class::name
を叩く必要があるらしい
降格
public
からprotected
にする
class A{
public:
int x;
}
class B:public A{
protected using A::x;
// reachable A.x from protected, private
}
public
からprivate
にする
class A{
public:
int x;
}
class B:public A{
private using A::x;
// reachable A.x from private
}
protected
からprivate
にする
class A{
protected:
int x;
}
class B:public A{
private using A::x;
// reachable A.x from private
}
使い道
部分的にprotected
をprivate
にしたいです,特に組込実装ではコード領域すらも節約する必要があるかと思います
一括で降格させる方法
つまり継承時にアクセス権限の規制をやれということで
多重継承
名前衝突や菱形問題の原因になるのでやめたい
もしくはせめて仮想継承をちゃんと実装したい
名前衝突
衝突しなかったらスコープ無しで派生クラスから呼べる
衝突したらスコープ派生元クラスを解決する必要がある
もし衝突してもエイリアスの作成は1個までならセーフ
class A{protected:int x;};
class B{protected:int x;};
class C:public A, public B{
public: using A::x; // -> OK
// public: using B::x; -> error
};
int main(void){
C c;
c.x = 0;
}
言い換えれば権限の変更は1個しかできないということ
むしろ今までのケースが「衝突しなかったらスコープ無しで派生クラスから呼べる」のを悪用して同名の再定義をしている
菱形問題
これらの例はA
とB
にそれぞれ独立にx
があった上でC
に合体させたせいで詰んでいるが,x
を持つA
からB
とC
に派生させた上でD
に合体させるような場合,(B
とC
が悪さをしない限り)仮想継承でx
は何とかなるかも
仮想継承
#include <iostream>
using namespace std;
class A{
protected:
int x;
};
class B: virtual public A{};
class C: virtual public A{};
class D: public B, public C{
private: using C::x;
protected: using B::x;
public: using A::x;
// both lines are equivalent in operation (why?)
// `public` is needed to be specified in the end
};
int main(void){
D d;
d.x = 1;
//d.A::x = 1; -> error if A::x is placed in protected
cout << d.x << endl;
};
A::x
の実体をB::x
もC::x
もD::x
も指すが,アクセス権限はA::x
とB::x
とC::x
とD::x
でそれぞれ設定され,かつusing
でエイリアスを作成するとその都度に設定が上書きされる(これでも実体は1つなので問題ない)
最終的にD
でpublic: using
するとD.x
を介して実体を操作できる