アクセス権限の意味
アクセス指定子をつけると設定できる
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を介して実体を操作できる