配列をポリモーフィックに扱ってはいけない。

873 名前: デフォルトの名無しさん 投稿日: 2007/09/23(日) 15:49:53

#include <stdio.h> 

class A { 
private: 
int a; 
public: 
A() { a = 10; } 
void put() { printf("%d\n", a); } 
virtual ~A() {} 
}; 

class B : public A { 
private: 
int b; 
public: 
virtual ~B() {} 
}; 

class D : public B {}; 

void a(A* d) 
{ 
for (int i = 0; i < 3; i++) { d[i].put(); } 
} 

int main(int argc, char* argv[]) 
{ 
D* d = new D[3]; 
a(d); 

delete [] d; 
return 0; 
} 

の時出力されるaの値は全て10を表示すると思ってるんですが・・・。
ならないのは何でなんでしょうか?
Visual Studio2005 SP1

878 名前: デフォルトの名無しさん 投稿日: 2007/09/23(日) 16:16:25
>>876
出力される値は
 10
 4290540
 -842150451
です。
875さんが言ってるとおりの動きをしてますね

875 名前: デフォルトの名無しさん [sage] 投稿日: 2007/09/23(日) 15:59:56
配列をポリモーフィックに扱ってはいけないから。

関数a()の中では、引数として渡された配列をA型の配列としてアクセスしているが、
実際はD型の配列なので、A::aとは違うところのメモリを読んで出力している可能性が高い。

877 名前: デフォルトの名無しさん 投稿日: 2007/09/23(日) 16:15:16
>>875
と言う事は配列ではなく1つ1つnewする必要があるってことですね?

879 名前: デフォルトの名無しさん [sage] 投稿日: 2007/09/23(日) 16:31:20
>>877 それもいいし、STLを使うとか、その場しのぎならD*でアクセスするとか

880 名前: デフォルトの名無しさん 投稿日: 2007/09/23(日) 16:35:25
>>879
STLではどうするんでしょうか?

今調べていたら、More Effectiveの項目3に書いてあるとネットでみたんですが
解決方法は規定クラスのポインタの配列で扱えば大丈夫ってわかりました。

881 名前: 879 [sage] 投稿日: 2007/09/23(日) 16:41:09
ポインタの配列をSTLで扱うことを考えてただけでした。そんなすごい方法じゃなくてごめん

882 名前: デフォルトの名無しさん 投稿日: 2007/09/23(日) 16:49:19
>>881
規定クラスのポインタの配列で試したらうまく動きました!!

ありがとうございました