////////////////////////////////////////////////////////////////////////////////
開発環境 : Visual C++ 6.0
動作環境 : Windows 98 Second Edition
MFC使用 MDIベース
////////////////////////////////////////////////////////////////////////////////
クラスAが次のようになっているとします。
class A
{
public:
A(A* pA);//同じクラスのポインタを引数に持つコンストラクタ
protected:
m_data;
};
A::A(A* pA)
{
m_data = pA->m_data;//データの代入
}
このように同じクラス内ならアクセス関数を使わなくても、そのままデータを代入できると思う
のですが、ここで、クラスAから派生したクラスBが次のようになっていたとします。
class B : public class A
{
public:
B(A* pA);
protected:
m_data;
};
B::B(A* pA)
{
m_data = pA->m_data;
}
これだとエラーになってしまいます。protectedで宣言しているのになぜできないのだろうと
思ってここの掲示板に書き込んでいたのですが、書き込んでいる途中で、
class B : public class A
{
public:
B(B* pA);//クラスBのポインタを引数にする
protected:
m_data;
};
B::B(B* pA)
{
m_data = pA->m_data;
}
だとエラーにはならないことに気づきました。とりあえず解決したので、書き込みを止めようか
とも思ったのですが、なぜ、上のではダメだったのかが少し気になりました。どなたかお忙しい
とは思いますが、もしわかれば教えてください。よろしくお願いします。
Aでprotectedにしたら当然Aのインスタンスからは
直接アクセスできません。
BをAからpublicで派生させればアクセス可能です。
ちなみにBをprotectedでAから派生させたらBからは
直接アクセスはできません。
さらにprivateで派生させたらAのpublicメンバにも
直接アクセスできなくなります。
http://black.sakura.ne.jp/~third/programming/cpp/cpp21.html
等を見ながら一度基礎固めすることをお勧めします。
いやスイマセン。ぜんぜん嘘の情報です。
私の認識が間違ってました。
もう一辺勉強してきます。
大変失礼いたしました。
euro2004さん、お返事、ありがとうございました。すみません、私の方の記述が間違っていま
した。大変申し訳ありません。次のように訂正させてください。
2つのクラス、AとBは次のようになっています。
//A.h
class A
{
private:
A();
protected:
m_data;
};
//A.cpp
A::A()
{
}
//B.h
class B : public class A
{
public:
B(B* pB);//問題の部分
};
//B.cpp
B::B(B* pB)
{
m_data = pB->m_data;
}
BはAをpublicで派生したクラスです。Aクラスはprotectedで宣言されたm_dataメンバと引数を
持たないデフォルトコンストラクタのみを持っています。
BクラスはAを派生したものなので、記述はありませんが、Aクラスと同じメンバm_dataを持って
います。Bクラスのコンストラクタで同じBクラスのポインタを持たせて、そのインスタンスのコ
ピーを作りたいと思っています。
上の記述だとエラーが出ずにうまく行くのですが、
//B.h
class B : public class A
{
public:
B(A* pA);//基本クラスのポインタを引数に持たせる
};
//B.cpp
B::B(A* pA)
{
m_data = pA->m_data;
}
というように基本クラスのポインタを持たせるとエラーが出ます。派生クラスの関数の中で基本
クラスのポインタを引数にすることはできないのでしょうか。
すみません、euro2004さんの書き込みを読む前に書き込んでしまいました。
こちらこそ、大変申し訳ありません。とても、混乱を招く記述をしてしまいました。
文章が長ったらしくなった分、誰も読んでくれなさそうな気もしますが、どなたか、もし、よけ
れば、よろしくお願いします。
先ほどは失礼しました。
環境は違いますが実験してみたところエラーは出ませんでした。
どういうエラーが出たのでしょうか?
環境
VC++6SP5 WinXPSP1, Win32ConsoleAP
内容
++++++++++++++++++++++++++++++++++
#include <stdio.h>
class A
{
public:
A(){}
A(int a)
{
m_data=a;
}
A(A *pA)
{
m_data = pA->m_data;
}
public:
int m_data;
};
class B :public A
{
public:
B(int b)
{
m_data=b;
}
B(A *pA)
{
m_data = pA->m_data;
}
B(B *pA)
{
m_data = pA->m_data;
}
public:
int m_data;
};
int main()
{
A a1(5);
A a2(&a1);
B b1(&a2);
return 0;
}
++++++++++++++++++++++++++++++++++
普通「protectedメンバはそのクラスと派生クラスからアクセス可能」
なんて書かれていますから、なんとなく不自然ですね。
以下のように考えると納得できるような気がします。
#思い付きなので、間違ってるかもしれません(^^;
A.外部からアクセスできるのはpublicのみである。
B.自クラスのメンバなら何でもアクセスできる。
C.親クラスのprotectedメンバは、自クラスのメンバとして
継承されるので、ルールBによりアクセスできる。
つまり、
「クラスAを継承すると、Aのm_dataにアクセスできるようになる」
ではなく、
「クラスAを継承すると、Aのm_dataはBに継承される。
Bは自分のm_dataにアクセスできるが、Aのm_dataには
依然としてアクセスできない」
と言うことです。
メンバ変数だとA::m_dataもB::m_dataも同じですが、
仮想関数の場合ちょっと変わってきます。
class A {
protected:
virtual void func();
};
class B : public A {
public:
void callFunc(A* pA) {
pA->func(); // このアクセスが許されるなら、
// pAがCのポインタの場合、
// 親子関係にないCのprotected関数を呼び出せてしまう
}
};
class C : public A {
protected:
virtual void func();
};
はまち様
返信が前後してしまってました (^^;
確かにおっしゃるようにエラーになりました。
dairygoods様
>「クラスAを継承すると、Aのm_dataはBに継承される。
> Bは自分のm_dataにアクセスできるが、Aのm_dataには
> 依然としてアクセスできない」
ですが、
B::foo()
{
mdata = A::m_data;
}
とすればできてしまいますが、これとは違う意味合いでしょうか?
上の例だと
「クラスAを継承すると、Aのm_dataはBに継承される。
Bは自分のm_dataにもAのm_dataにもアクセスできるが、
同一インスタンス内のものに限られる。」
となると思うのですが、これだと
B::foo(B* pB)
{
m_data = pB->m_data;
pB->m_data = ・・・
}
とすると理論が破綻してしまいます。というより
class Bのインスタンス,b1, b2があった場合に
一方が他方のprotectedメンバを扱えてしまうので
カプセル化の概念に反するかと思うのですが。
なぜコンパイラが2番目の例を許すのか、
思いつきでもかまいませんので意見をいただければうれしいです。
アクセス指定はクラスごとに行われるからではないかと。
> B::foo()
> {
> mdata = A::m_data;
> }
> とすればできてしまいますが、これとは違う意味合いでしょうか?
いえ、そこまで考えていませんでした(^^;
「A::m_data」という表記は「クラスAから継承した自分のm_data」
という意味と考えます。(強引かな)
> 上の例だと
> 「クラスAを継承すると、Aのm_dataはBに継承される。
> Bは自分のm_dataにもAのm_dataにもアクセスできるが、
> 同一インスタンス内のものに限られる。」
> となると思うのですが、これだと
いいえ。インスタンスについては何も言っていません。
C++にはインスタンス単位のアクセス制御はありませんし。
(そもそも、ポインタを受け取ったらコンパイル時に
同一インスタンスかどうか判定できない)
> class B : public class A
^^^^^
文法がが間違っているようです。正しくは…。
class B : public A
…で良いのでは?
まだC++歴も短いので、いまいち自信が無いのですが、基底クラスの
データメンバと派生クラスのデータメンバに同名のメンバがあるときは、
派生クラスのメンバで基底クラスのメンバを隠すのではなかったでしたっ
け?
グローバル変数と、ローカル変数で同名な変数名の時に、ローカル変数
がグローバル変数を隠すのと同じように…。
# ところで、メンバ関数だけでなくデータメンバの場合もオーバーライド
#っていうのかな?(^^;;;
それから、クラスの継承はあくまで差分定義というような意味合いで、
基底に足りないものを派生で追加するという感じだったはずです。
つまり基底クラスにあるものはすべて派生クラスも持っていて、派生ク
ラスからはprivateで定義されたメンバ以外自由にアクセス出来るのでは
なかったかと…。
> 普通「protectedメンバはそのクラスと派生クラスからアクセス可能」
> なんて書かれていますから、なんとなく不自然ですね。
自分のクラス内でのみ考えるなら、実質「private」と「public」の二つ
しか無いと考えるのがわかりやすいかもしれませんね。
実際「protected」が生きてくるのは派生された時だけですし、派生クラ
スから基底クラスにアクセス出来るのは「private」以外と丸暗記する方が、
楽ちんかもしれないです。
> public:
> int m_data;
って、Bクラスでオーバーライドしていますが、virutal をつけた時のように
ポリモルフィズムは有効になりません。B を A* にキャストしたら A::m_data
にアクセスします。B::m_data にはなりません。
なぜそうなるかは全然わかりませんね(^^ゞ
打開策は friend class ですかね。
×なぜそうなるかは全然わかりませんね(^^ゞ
なにいってんだが、わかりませんね。書き間違いました。
> 普通「protectedメンバはそのクラスと派生クラスからアクセス可能」
のことをさしていっているつもりです。レスを汚くして申し訳ありません。
何が疑問なのかいまいちわからないんですけど。。。
1輪車クラスから2輪車クラスを継承で作る
1輪車クラスには、車輪メンバがある
2輪車クラスで、もうひとつ車輪メンバを増やした
2輪車クラスは、元1輪車クラスの車輪と自分の車輪をふたつ持っている
2輪車クラスが自分のふたつの車輪をいじるのは自由である
けれど、2輪車クラスが1輪車クラスの車輪をいじるのは自由ではない
という比喩で納得いきません?