![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e8efa67)
![](http://oshiete.xgoo.jp/images/v2/common/profile/M/noimageicon_setting_03.png?e8efa67)
以下のように、継承関係を作ります。
---------------------------------------
#include <iostream>
#include <list>
#include <vector>
using namespace std;
struct Base {
virtual ~Base() = 0;
};
Base::~Base() {}
struct Sub1 : Base {
int v;
Sub1(int i) { v = i; }
};
struct Sub2 : Base {
double v;
Sub2(double d) { v = d; }
};
---------------------------------------
この場合、
Sub1, Sub2 のインスタンスをなにかコンテナに入れたい場合は、一般的には以下のように書けばいいのでしょうか?
----------------------
list<Base*> l;
vector<Base*> v;
Sub1 s1(3);
Sub2 s2(4.4);
l.push_back(&s1);
l.push_back(&s2);
v.push_back(&s1);
v.push_back(&s2);
----------------------
list<Base>, vector<Base>も試しましたが
list<Base> は宣言したところで
vector<Base> は push_back() したところで
コンパイルエラーになりました。
これは、こういうものなのでしょうか?
むしろ、struct(もしくはclass)の書き方を変えたりすれば、問題なくなったりするのでしょうか?
全体としては、C++は参照などあって、どいう場合にポインタ使うべきなのかそういう部分に混乱しているような気もします。
いろいろ質問してしまって、申し分けないですがなにか
ひとつでも答えられるものがあれば回答してもらえると
ありがたいです。
No.1ベストアンサー
- 回答日時:
> これは、こういうものなのでしょうか?
そういうものです。vector<Base>で格納しようとすると、Baseのインスタンスを作ろうとするのでコンパイルに失敗します。
書き方をかえるという意味ではBaseを純粋仮想でなくすればコンパイルは通りますが、
(Baseを実体化するので)Sub1やSub22のポリモフィックな動作はせず、
「スライシング」と呼ばれる問題を引き起こします。(コンパイルが通るだけで通常は解決策ではありません)
また、一般にポインタを格納する場合、new等をすることになりdeleteの問題が出ますが、
「STLコンテナにはstd::auto_ptrは使えない」仕様です。
例外はあるものの、多くの場合boost::shared_ptrのような「スマートポインタ」を使うとすっきりします。
std::list<boost::shared_ptr<Base> > l;
std::vector<boost::shared_ptr<Base> > v;
参考URL:http://www.boost.org
> そういうものです。vector<Base>で格納しようとすると、Baseのインスタンスを作ろうとするのでコンパイルに失敗します。
なるほど、vector<Base>を作ろうとしたときでなく、格納しようとした時点でインスタンスを作るのですか。
> 書き方をかえるという意味ではBaseを純粋仮想でなくすればコンパイルは通りますが、
ああ、これもそういえばやっていたのですが、インターネットの文章など見るとやっぱり、
純粋仮想関数など使っている様子だったので、なにか問題があるのかと思っていたのですが、そういう問題があるのですね。
非常に参考になりました。
> また、一般にポインタを格納する場合、new等をすることになりdeleteの問題が出ますが、
> 「STLコンテナにはstd::auto_ptrは使えない」仕様です。
>
> 例外はあるものの、多くの場合boost::shared_ptrのような「スマートポインタ」を使うとすっきりします。
こういうものがあるのですね。
スコープから外れたら、スタックに取っているオブジェクトのデストラクタ呼ばれるので
auto_ptr って意味あるのかな?と思ってたのですが。
shared_ptrというのを使えばいいのですね。
(あい変らずauto_ptrの存在意義は分からないのですが)
でも、shared_ptrも大きいか小さいか分かりませんが、コストがあるようなのでよく考えて、使うべきところで使うようにしたい思います。
ありがとうございました。
No.6
- 回答日時:
X のサブクラスとして Y を宣言した場合, クラスY のオブジェクトを「X* あるいは X&」で使えば Y のメンバ関数が呼び出されますが, 「X」で使うと X のメンバ関数しか呼び出せません. 「クラスのオブジェクトそのもの」として使うのか, それとも「ポインタや参照」で使うかということで明確に区別する必要があります.
で, vector<Base> の時点でエラーにすべきだとは思うんだけど.... 実装上, 難しいんじゃないかなぁ? 少なくとも, 「宣言した時点」でエラーにするのは困難だと思う. list<Base> は多分内部的に Base を作ろうとしてエラーになるけど, vector<Base> は「Base を直接作る」とは限らない (この辺, デフォルトコンストラクタが要求されていないことと関連します) ですから. バルクでメモリをもらってきて「必要に応じてコピーコンストラクタを呼び出す」という実装かもしれないですし, このような実装でも規格上問題ありませんから.
> 「クラスのオブジェクトそのもの」として使うのか, それとも「ポインタや参照」で使うかということで明確に区別する必要があります.
ANo.1のスライシングの問題ですね。(昨日覚えた事なので自信ないですが。)
半端にコピーされること自体は多分問題ないけど、
Yのメンバ関数で、XにないY独自の領域にアクセスしようとすると困るので多分そうなっているんだろうと考えています。
> 少なくとも, 「宣言した時点」でエラーにするのは困難だと思う.
コンストラクタにプリント入れて list<Base>, vector<Base> をやってみましたが、コンストラクタは動いていない様子でした。
listの方は、番兵かなにか作っていてそいういう部分で困るのかもしれないですね。(完全に勘です。STLのソースは良く分かりませんでした。)
ありがとうございました。
No.5
- 回答日時:
# 休出とかするものじゃない…今日はメタメタです。
申し訳ない。> vector<Base>を作る時点/格納の時点ということで言えば、作る時点でエラーになります。
これは、Baseが純粋仮想関数を持っていると、push_backなどしなくても
list<Base> l;
vector<Base> v;
だけでエラーになります(なるべきです)
> コピーコンストラクタではないかと思ったのですが、これも違いますか?
ごめんなさい。こっちはコピーコンストラクタの間違いでした…orz
> これは、Baseが純粋仮想関数を持っていると、push_backなどしなくても
> list<Base> l;
> vector<Base> v;
> だけでエラーになります(なるべきです)
そうですね、どうせ push_back などできないなら、宣言の時点でエラーにしてくれた方が親切です。
ただ、そうならないのは僕が多分そういう実装の STL を使っているということなんでしょうね。
ちなみに僕は gcc4.1.1 で libstdc++6.0.8 を使っています。
ありがというございました。
No.4
- 回答日時:
この手の問題をクリアするには、既に回答が出ているように、boost::shared_ptrあるいはstd::tr1::shared_ptr(可能であれば後者の方が望ましいかも)を使うのが正攻法だと思います。
shared_ptrを使えば、仮想デストラクタがなくても、うまく解体できるようになりますし、いろいろメリットがあります。サイズ効率がどうしても気になるのであれば、boost::ptr_vectorという選択肢もあるにはあります。使い勝手がいまいちなので、どちらかといえば、それほどお勧めはしませんが...。
> std::tr1::shared_ptr
これも
#include <tr1/memory>
で使える様子でした
> shared_ptrを使えば、仮想デストラクタがなくても、うまく解体できるようになりますし、いろいろメリットがあります。
この、shared_ptrは今日知ってリファレンスカウントをもっているというのが分かったのですが、それ以外にも機能があるのですね。
http://www.zeroscape.org/cgi-bin/wiki/wiki.cgi?p …
多分ここに書いてあるような事だと思いますが
virtual でないデストラクタしかなくても、よきにはからってくれるようでした。
実装方法は全く検討もつきませんが、凄いことは分かりました。
ありがとうございました。
No.3
- 回答日時:
vector とか list とかのコンテナクラスに入れるためには, コピーコンストラクタが必要です. デフォルトコンストラクタはなくても動作することはすると思うけど....
もっとも, 仮想関数があるのでポインタを使わないと予定した動作はしないと思いますが.
やっぱり、コピーコンストラクタが必要なのですか。
> もっとも, 仮想関数があるのでポインタを使わないと予定した動作はしないと思いますが.
これは、http://www.aerith.net/design/argument-j.html にあるような予期せずスーパークラスの関数が呼ばれてしまう、ということでしょうか?
僕が調べたところ、スーパークラスの関数が呼ばれる場合は直接スーパークラスの関数が呼ばれていて、ポインタ経由でうまくいっている場合は仮想関数テーブル経由になっているみたいでした。
これが、コンパイラなどに依存することのかは分からないですが
No.2
- 回答日時:
> なるほど、vector<Base>を作ろうとしたときでなく、
> 格納しようとした時点でインスタンスを作るのですか。
すみません。言葉が悪かったです。
vector<Base>を作る時点/格納の時点ということで言えば、作る時点でエラーになります。
# (内部的な動作に必要なので)デフォルトコンストラクタで生成できないオブジェクトは格納できません。
> あい変らずauto_ptrの存在意義は分からないのですが
動的生成したオブジェクトを関数の戻り値で返して、かつ解放を強制したい、とか。
ポリモフィックに動作させるために動的にnewしたいけど、スコープを抜けたら自動で解放したいとか。
例外がおきても安全にオブジェクトが解放されるようにしたいとか。
まぁ、スタック上のオブジェクトでカバーできない動的なオブジェクトを、
お手軽にスタック上にあるかのような使い方をするためのものだと思いますが。
# C++の場合、他言語のようにオブジェクトがデフォルトで参照というわけではないので、
# 「参照にした」際に発生する手間の軽減策(のひとつ)がauto_ptrかなという気はします。
> vector<Base>を作る時点/格納の時点ということで言えば、作る時点でエラーになります。
> # (内部的な動作に必要なので)デフォルトコンストラクタで生成できないオブジェクトは格納できません。
vectorの場合は、push_back()の段階で、コンパイルエラーだったので格納するときのいうのは納得がいっていたのですが、違うのですか?
また、コピーコンストラクタを作って、その中で cout<< でプリントを入れるとpush_back()したときに、それ(コピーコンストラクタ)が動いているようだったのでデフォルトコンストラクタではなく、デフォルトコピーコンストラクタではないかと思ったのですが、これも違いますか?
デフォルトコンストラクタだと、引数付きコンストラクタなどを1つでも定義したclass,structだとvector,listが作れなくなると思ったのですが。
auto_ptrについては、用途が思いうかびました。
ファクトリーパターンなど、ポインタでしかインスタンスの操作が
想定されてない場合は、必要かもしれないと思いました。
ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- インターネットビジネス BASEの機能の相談です 1 2023/04/23 14:58
- C言語・C++・C# プログラミングの問題です。写真のプログラムの1から10を下のように入力しましたがプログラムが上手くい 3 2022/07/01 23:31
- 英語 in the head の意味 4 2023/07/15 07:52
- インターネットビジネス 超初心者です。 BASEでネットショップを考えております。(シイレル)と言う食品飼育サイトから食品食 3 2022/07/19 22:40
- 英語 After exporting the planned implant position, a to 2 2022/10/31 17:48
- その他(ネットショッピング・通販・ECサイト) クリックポストでBASEやストアー等で売れた商品の発送元をシールのラベルに印字して発送したいですが、 1 2022/06/04 23:49
- PHP 書籍よりも より良い htmlspecialchars の変更を 1 2022/04/18 02:28
- その他(車) 軽自動車に普通車のタイヤ+ホイールsetは装着可能でしょうか? 4 2022/12/10 22:40
- 大学・短大 C言語線形リストの問題です 3 2022/12/22 00:45
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
EXCEL VBAにて動的にCheckBOXを...
-
多人数のじゃんけんプログラム
-
VBA 同じ名前のオブジェクトを...
-
Visual Studioでのbmpファイル...
-
C#でフォームのオブジェクト名...
-
C++ 多態とstlのコンテナについて
-
VBAのWindowオブジェクトとWork...
-
COMコンポーネントって何?
-
パワーポイントのVBAでテキスト...
-
Setステートメントの使い方につ...
-
VBAでvlookup関数から、別シー...
-
Google Apps Scriptの時刻の計算
-
ビジュアルC++でボタンの有...
-
Excelで =EMBED("Acrobat Docu...
-
CoCreateInstanceでエラーになる。
-
ADO オブジェクトの渡し方
-
JAVAからHTMLへ値を返す方法
-
ワイルドカード<?>と型パラメー...
-
戻り値がクラスオブジェクト
-
withを入れ子にして使う方法
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
0 == False はいいけど
-
パワーポイントのVBAでテキスト...
-
C#でフォームのオブジェクト名...
-
Excelで =EMBED("Acrobat Docu...
-
VBAのWindowオブジェクトとWork...
-
JAVAからHTMLへ値を返す方法
-
EXCEL VBAにて動的にCheckBOXを...
-
ワイルドカード<?>と型パラメー...
-
COMコンポーネントって何?
-
VBA 同じ名前のオブジェクトを...
-
Object型からDouble型へのキャスト
-
ビジュアルC++でボタンの有...
-
error C2712: オブジェクト ア...
-
オブジェクト名をforループ内で...
-
bmp画像をjpegやpng画像に圧縮...
-
戻り値がクラスオブジェクト
-
Vbで通常使用するプリンターを...
-
時間帯判定をする。
-
Webアプリケーションのエラーメ...
-
LISTBOXの内容が更新されま...
おすすめ情報