Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

コンストラクタからのインスタンスメソッドの呼び出しは必要か?

334 views
Skip to first unread message

pegacorn

unread,
Mar 8, 2007, 9:53:19 PM3/8/07
to
こんにちは。コンストラクタに関して教えてください。

コンストラクタからインスタンスメソッドを呼び出す場合には下記のような
注意が必要ですが、そもそもそんな注意が必要な仕様にしてまで呼び出せる
ようにする必要があるのでしょうか?
単純に呼び出せないようにすれば良いのではないでしょうか?


■コンストラクタからのインスタンスメソッド呼び出しの注意
◇C++等の場合
メソッドがサブクラスでオーバーライドされていても、サブクラスの
メソッドではなく自クラスのメソッドが呼び出される。

◇Ruby,Java等の場合
メソッドがサブクラスでオーバーライドされている場合、サブクラスの
メソッドが呼び出されるが、サブクラスでのコンストラクトが完了して
いない可能性がある。


■例
◇C++の場合
・ソースプログラム
#include <string>
#include <iostream>

class SuperClass
{
std::string x_;
public:
SuperClass(const std::string &x):
x_(x)
{
method();
}
virtual ~SuperClass() {}

virtual void method() const {
std::cout << "in SuperClass#method\n";
std::cout << x_ << "\n";
}
};

class SubClass: public SuperClass
{
std::string y_;
public:
SubClass(const std::string &y):
SuperClass(y),
y_(y + "def")
{
}
virtual ~SubClass() {}

virtual void method() const {
std::cout << "in SubClass#method\n";
std::cout << y_ << "\n";
}
};

int main()
{
SubClass obj("abc");
obj.method();
}

・実行結果
in SuperClass#method
abc
in SubClass#method
abcdef

◇Rubyの場合
・ソースプログラム
#/usr/local/bin/ruby

class SuperClass
def initialize(x)
@x = x
method()
end

def method
puts 'in SuperClass#method'
puts @x
end
end

class SubClass < SuperClass
def initialize(y)
super(y)
@y = y + 'def'
end

def method
puts 'in SubClass#method'
puts @y
end
end

obj = SubClass.new('abc')
obj.method

・実行結果
in SubClass#method
nil
in SubClass#method
abcdef


--
pegacorn

Masamichi Takatsu

unread,
Mar 8, 2007, 10:41:16 PM3/8/07
to
たかつです。

C++使いの意見ですが、

記事 <1173408799....@30g2000cwc.googlegroups.com> で
"pegacorn"さんは書きました

> コンストラクタからインスタンスメソッドを呼び出す場合には下記のような
> 注意が必要ですが、そもそもそんな注意が必要な仕様にしてまで呼び出せる
> ようにする必要があるのでしょうか?
> 単純に呼び出せないようにすれば良いのではないでしょうか?

引数の異なる複数のコンストラクタがある場合に、それぞれのコンストラクタに
いちいち初期化コードを記述するのは無駄が多いし保守性が悪くなるので、

共通の初期化ルーチンはメソッドとして用意して、それぞれのコンストラクタから
呼び出す、ということはよくやってます。
例えば、メンバ変数が増えたりした時に、全てのコンストラクタにそのメンバの
初期化コードを書くのは手間がかかりますし、ヘタすると初期化ミスの元ですし。

あまり良い例かわかりませんが、

class array {
int *p;
int s;
init() { p = NULL; s = 0; }
destroy() { delete [] p; }
alloc(int size) { destroy(); p = new int[s = size];}
copy(const aclass &src) { alloc(src.s); memcpy(p, src.p, sizeof(*p)*s);}
public:
array() {init();}
array(int size) {init(); alloc(size);}
array(const array &src) {init(); copy(src);}
~array() { destroy(); }
array &operator=(const array &src) { copy(src); return *this;}
};

みたいな感じ。それぞれの機能を書き下すより効率は悪くなってますが、
それよりも保守性重視ってことで。


PROJECT TEAM DoGA 高津正道 ta...@doga.jp
PROJECT TEAM DoGAのホームページ → http://doga.jp/
3月9日(金) 今日のマーフィーの法則 [収支力学の第1法則]
思いがけない収入があると、思いがけない同額の支出がある。

pegacorn

unread,
Mar 9, 2007, 8:26:41 AM3/9/07
to
On 3月9日, 午後12:41, Masamichi Takatsu <t...@doga.jp> wrote:
> 引数の異なる複数のコンストラクタがある場合に、それぞれのコンストラクタに
> いちいち初期化コードを記述するのは無駄が多いし保守性が悪くなるので、
>
> 共通の初期化ルーチンはメソッドとして用意して、それぞれのコンストラクタから
> 呼び出す、ということはよくやってます。

私も時々やってました。
でも、それってこの件の典型的なはまりパターンではないでしょうか?

・ソースプログラム
#include <string>
#include <iostream>

class SuperClass
{
std::string x_;
public:

SuperClass()
{
initialize();
}
virtual ~SuperClass() {}

virtual void initialize() {
x_ = "abc";
}

virtual void put_property() const {
std::cout << "x_ = " << x_ << "\n";
}
};

class SubClass: public SuperClass
{
std::string y_;
public:

SubClass():
SuperClass()
{
}
virtual ~SubClass() {}

virtual void initialize() {
SuperClass::initialize();
y_ = "def";
}

virtual void put_property() const {
SuperClass::put_property();
std::cout << "y_ = " << y_ << "\n";
}
};

int main()
{
SubClass obj;
obj.put_property();
std::cout << "----\n";
obj.initialize();
obj.put_property();
}

・実行結果
x_ = abc
y_ =
----
x_ = abc
y_ = def


--
pegacorn

pegacorn

unread,
Mar 11, 2007, 5:03:56 AM3/11/07
to
On 3月9日, 午後1:48, k...@ie.u-ryukyu.ac.jp (Shinji KONO) wrote:
> In article <070309124116.M1200...@XP.doga.jp>, Masamichi Takatsu <t...@doga.jp> writes

>
> > 引数の異なる複数のコンストラクタがある場合に、それぞれのコンストラクタに
> > いちいち初期化コードを記述するのは無駄が多いし保守性が悪くなるので、
> > 共通の初期化ルーチンはメソッドとして用意して、それぞれのコンストラクタから
> > 呼び出す、ということはよくやってます。
>
> それは必須だと思います。コンストラクタは入口に過ぎないので、
> 実際の初期化は別なメソッドで行うべきでしょうね。

書籍版 C++ FAQ では、一部例外を除いて初期化並びを使う事を推奨しています。
電子版(comp.lang.c++)に書いてあるかは未確認ですが。
理由はこんな感じ。
・初期化並びを使わないと処理速度が遅くなる。
・const データメンバは初期化並びでしか初期化できない。
・リファレンスデータメンバは初期化並びでしか初期化できない。


--
pegacorn

Shinji KONO

unread,
May 16, 2007, 9:03:41 PM5/16/07
to
河野真治 @ 琉球大学情報工学です。

PL/Iの再来とか、C++はソフトウェア工学を10年後退させたとか、
まぁ、そんな言われ方をしてますが...

http://tinyurl.com/2e38yw

が有名か...

もともとのCには、モジュールという概念がなく、大域変数をモジ
ュール化出来ないっていう欠点がある。static で、ファイルの中
に閉じ込めることは出来るんだけど。なので、そのあたりを改良
したものが欲しいってのはある。

C++ の同時期に、Objective C とか Cob とか、いろいろ提案され
てました。大学院時代の同僚も同じようなことしてました。AT&T
Bell Lab をback ground に、ゴリ押し的に広まった。最初は、C+
+ からCへ変換する cfront とかいう実装だったはず。

Ojective C がSmalltalkを意識した実装になっているのに比べて、
「Cの構造体と、構造体経由の間接呼び出しを使った、簡易実装」
という感じになってます。なので、Cの構造体の欠点がそのまま残
っている。この程度だったら、自分で、構造体でオブジェクトを
作った方がいいと思う。

初期の有名なC++で実装されたアプリというと、InterViews とい
うGUI Toolkit と、それで実装された idraw ですね。このidraw
が「C++ のversionがあがるたびに、動かなくなる」という技を出
す。いいソフトだったんだけどな。PostScript 自体がidrawのフ
ァイルフォーマットになっているという。k2d とかいう名前であ
るらしいが見つけられませんでした。

でも、C++ が、真のダメさ加減を発揮するのは、Template を採用
してからだと思う。制御不可能なほど、ものごとをこじれさせる
感じです。それまででも十分に複雑だったのに、さらに、Template
を覚えないといけないんですか? タイプ変数を導入できるので、
その部分は便利といえば便利なんだが... まぁ、マクロだと思え
ば、その場で展開されるというだけだとも言えるのだが。

  template<typename _Tp>
  complex<_Tp>&
  complex<_Tp>::operator/=(const _Tp& __t)
  {
   _M_real /= __t;
   _M_imag /= __t;
   return *this;
  }

このoperator overrideも「見た目通りに動かない」C++ と言う感
じを良く出してます。この中で bug ったりしたら、debug のやり
ようがないです。引数の型が異なると、異なる関数を呼び出す polymorphism
も C++ の場合は裏目にでていると思う。

Effective C++ は必須なんだけど、それを読んでも、なぁ...

自分で係わることは幸い少なかったんだが、C++ が噛んでいるプ
ロジェクトで幸せにはなれないと思う。Acsis C++ の時は、逃げ
てしまいました。

継承とか、大域変数のモジュール化とかで使いたいことは使いた
いんだけど、

 ゴミで一杯の巨大な仕様

が、すべてをぶち壊しにしていると思う。Objective C が良くで
きていただけに、C++ が広まったのは残念です。

ま、今は、Java に逃げるという手があるから、まだまし。ってい
うか、今時、C++を使うのは、Windows な開発者だけだろ?

---
Shinji KONO @ Information Engineering, University of the Ryukyus
河野真治 @ 琉球大学工学部情報工学科

ku...@gssm.otsuka.tsukuba.ac.jp

unread,
May 16, 2007, 11:54:15 PM5/16/07
to
久野です。

ko...@ie.u-ryukyu.ac.jpさん:
> PL/Iの再来とか、C++はソフトウェア工学を10年後退させたとか、
> まぁ、そんな言われ方をしてますが...

言語メカニズム的に面白いです。あのテンプレート世界の発展は予想
できなかった。

> もともとのCには、モジュールという概念がなく、大域変数をモジ
> ュール化出来ないっていう欠点がある。static で、ファイルの中
> に閉じ込めることは出来るんだけど。なので、そのあたりを改良
> したものが欲しいってのはある。

それはC++ではnamespaceですね。

> 初期の有名なC++で実装されたアプリというと、InterViews とい
> うGUI Toolkit と、それで実装された idraw ですね。このidraw
> が「C++ のversionがあがるたびに、動かなくなる」という技を出
> す。いいソフトだったんだけどな。PostScript 自体がidrawのフ
> ァイルフォーマットになっているという。k2d とかいう名前であ
> るらしいが見つけられませんでした。

そりゃ何か違うんでは。idraw → 日本語idraw (kdraw)、だけでしょ。
私がkdrawをキーボードで操れるように直したのがk2dなんだけど。

> でも、C++ が、真のダメさ加減を発揮するのは、Template を採用
> してからだと思う。制御不可能なほど、ものごとをこじれさせる
> 感じです。それまででも十分に複雑だったのに、さらに、Template
> を覚えないといけないんですか? タイプ変数を導入できるので、
> その部分は便利といえば便利なんだが... まぁ、マクロだと思え
> ば、その場で展開されるというだけだとも言えるのだが。

だけだとも言えるけど、実質はだけじゃないんですよね。テンプレー
トメタプログラミングとかすごい。

>   template<typename _Tp>
>   complex<_Tp>&
>   complex<_Tp>::operator/=(const _Tp& __t)
>   {
>    _M_real /= __t;
>    _M_imag /= __t;
>    return *this;
>   }

> このoperator overrideも「見た目通りに動かない」C++ と言う感
> じを良く出してます。この中で bug ったりしたら、debug のやり
> ようがないです。引数の型が異なると、異なる関数を呼び出す polymorphism
> も C++ の場合は裏目にでていると思う。

デバッグ大変というのは本当そういう感じですよね。

> Effective C++ は必須なんだけど、それを読んでも、なぁ...
> 自分で係わることは幸い少なかったんだが、C++ が噛んでいるプ
> ロジェクトで幸せにはなれないと思う。Acsis C++ の時は、逃げ
> てしまいました。

まあ解らないでもないけど。

> 継承とか、大域変数のモジュール化とかで使いたいことは使いた
> いんだけど、

継承、使いたいですかねえ。モジュール化だけならnamespaceだけ使
えばいいのでは。C++はすべて入っているから、必要なところだけ使う
というのはありと思いますよ。

> が、すべてをぶち壊しにしていると思う。Objective C が良くで
> きていただけに、C++ が広まったのは残念です。
> ま、今は、Java に逃げるという手があるから、まだまし。ってい
> うか、今時、C++を使うのは、Windows な開発者だけだろ?

そうでもないのでは。私、JavaのGenericsとかいまいちだと思ってい
るので最近C++に好意的です。"Design & Evolution of C++" 読みまし
たか?

でもヘタレな私が書くのはJavaだな。 久野

Message has been deleted
Message has been deleted

pegacorn

unread,
May 17, 2007, 8:29:32 AM5/17/07
to
On 5月17日, 午前10:03, k...@ie.u-ryukyu.ac.jp (Shinji KONO) wrote:
> ま、今は、Java に逃げるという手があるから、まだまし。ってい
> うか、今時、C++を使うのは、Windows な開発者だけだろ?

楽しいですか?
http://slashdot.jp/developers/article.pl?sid=06/12/14/1233207

0 new messages