質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

14598閲覧

シングルトンパターンを持つ基底クラスを継承したい

penpen

総合スコア8

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2015/05/03 08:56

今作成しているプログラムでシングルトンパターンを持つ基底クラスを継承したクラスを作る必要が出てきたので,こちらのサイト(http://glass5er.hatenablog.com/entry/20130630/1372556362))を参考にしていたのですが,このサイトで扱われているソースコードに対して1つ疑問があったので質問しました.

サイトのソースコードは以下のようになっています.

lang

1#include <iostream> 2#include <string> 3 4using namespace std; 5 6//---------------- 7 8template <class U> 9class SingletonParent 10{ 11 public: 12 static U* getInstance() { 13 static U instance; 14 return &instance; 15 } 16 17 protected: 18 //-- template func in template class available 19 template<typename T> void print2Times(T v); 20 21 SingletonParent() { 22 base_str = string("BASE"); 23 } 24 virtual ~SingletonParent() {} 25 string base_str; 26}; 27 28 29//-- use template succession 30class SingletonChild : public SingletonParent<SingletonChild> { 31 public: 32 SingletonChild() { 33 child_value = 0; 34 } 35 ~SingletonChild() {} 36 37 void set(int v) { child_value = v; } 38 int get() { return child_value; } 39 40 void print() { 41 print2Times(base_str); 42 print2Times(child_value); 43 } 44 private: 45 int child_value; 46}; 47 48//-- when defining template func in template class, 49//-- 2 template declaraton required 50template<class U> template<typename T> 51void 52SingletonParent<U>::print2Times(T v) 53{ 54 cout << v << v << endl; 55} 56 57 58//---------------- 59 60 61int 62main(int argc, char const* argv[]) 63{ 64 //-- actually the same instance 65 SingletonChild *inst1 = SingletonChild::getInstance(); 66 SingletonChild *inst2 = SingletonChild::getInstance(); 67 68 //-- both 0 69 cout << inst1->get() << endl; 70 cout << inst2->get() << endl; 71 72 //-- BASEBASE, 00 73 inst1->print(); 74 75 inst2->set(3); 76 77 //-- both 3 78 cout << inst1->get() << endl; 79 cout << inst2->get() << endl; 80 81 //-- BASEBASE, 33 82 inst1->print(); 83 return 0; 84} 85

派生クラスのコンストラクタがpublicになっているので,これではシングルトンの意味がないと思い,privateに変更したところ,下記のようにSingletonChildのコンストラクタがprivateだからアクセスできないと怒られました...
私としては,基底クラスから継承したgetInstance()を使って派生クラスの内部からSingletonChild()にアクセスしているので,問題ないと考えていたのですが,どのあたりが間違っているのでしょうか?

g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/main.d" -MT"src/main.d" -o "src/main.o" "../src/main.cpp"
../src/main.cpp: In instantiation of ‘static U* SingletonParent<U>::getInstance() [with U = SingletonChild]’:
../src/main.cpp:93:43: required from here
../src/main.cpp:70:5: error: ‘SingletonChild::SingletonChild()’ is private
SingletonChild() {
^
../src/main.cpp:40:16: error: within this context
static U instance;
^
make: *** [src/main.o] エラー 1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

私が昔ハマった勘違いを同じようにされているかもしれないので投稿します。

私は昔classのprivateやprotected宣言をクラスのインスタンスから見た公開範囲の指定だと考えていました。しかし、実際には同一クラスであれば別のインスタンスからも変更できます。

lang

1class Hoge 2{ 3private: 4 int _value; 5public: 6 Hoge(int value): _value(value) {} 7 8 int GetValue() { _value; } 9 void AddsTo(Hoge &obj) 10 { 11 // 別のインスタンスのprivateメンバを変更する 12 // ※昔は別インスタンスなのでできないと思っていた 13 obj._value += this->_value; 14 } 15}; 16 17void main() 18{ 19 Hoge a(10); 20 Hoge b(5); 21 22 a.AddsTo(b); 23 printf("%d", b.GetValue()); // 15が表示される 24}

class の private や protected の宣言は、クラス定義から見た公開範囲を指定しています。
privateは継承関係無く同一クラス内のみ、protectedは継承関係にある派生クラス側への許可のみで、そのためにfriend宣言もクラス定義間の条件付けになっています。
このために、派生クラス側の private な指定には、基底クラス側からはアクセスできません。
基底クラス側に処理を公開する方法は、public宣言か、friend宣言しかありません。

投稿2015/05/05 02:52

編集2015/05/05 04:14
haru666

総合スコア1591

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

penpen

2015/05/05 06:00

回答ありがとうございます. 指摘されたとおり,今まで私はprivateやprotected宣言を"クラスのインスタンスから見た公開範囲の指定"と考えていたようです. 指摘されるまではそのように考えていたことにすら気がつかなかったのですが... private や protected の宣言は、”クラス定義から見た公開範囲を指定”と考えると辻褄があって色々とスッキリしました. このような誤って理解している場合は自分ではなかなか気が付けないので大変ありがたいです. 本当にありがとうございました.
guest

0

privateメンバは、自クラス内部 または friend宣言したクラス からしかアクセスできません。

SingletonParent<SingletonChild>クラスをfriend宣言すれば、仰っている内容は実現できます。

lang

1class SingletonChild : public SingletonParent<SingletonChild> { 2 friend class SingletonParent<SingletonChild>; // 追加 3 private: // privateに変更 4 SingletonChild() { 5 child_value = 0; 6 } 7 public: 8 ...

投稿2015/05/03 14:31

yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

penpen

2015/05/03 15:16

回答ありがとうございます. 私は,基底クラスから継承したメンバは派生クラスのメンバになる(つまり,getInstance()のアクセスは内部からのアクセスになる)と理解していたのですが,誤った理解をしていたみたいですね... 実際の継承のメカニズムはどのようになっているのでしょうか? 参考書やネットには継承の内部的な話はなかなか載っていないので,教えていただけるとありがたいです.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問