dポイントプレゼントキャンペーン実施中!

c++ で例えば、

class A
{
public:
 virtual ~A() {}
};

class B
{
public:
 virtual ~B() {}
 virtual B& hoge() = 0;
};


class D:
 public A,
 public B
{
public:
 virtual D& hoge() // この戻り値でエラー
 {
  ...;
  return *this;
 }
};

のようにコードを書いたとします。

そして、これを gcc 3.3 でコンパイルしたところ「ゴメン。共変はサポートしてないんだ」って感じでエラーとなってしまいました(gcc 3.2 では問題を孕んでたくせに、何も言わずにコンパイル通ってました)。

この共変の意味や、その実際の挙動、問題点等は判ったのですが、では一体、この様な場合にどのようにコードを修正するのが正しいのか思い至りません。

どなたか、私ならって言うお考えがあればご教示願えないでしょうか?

ちなみに、コンパイラーを変えるってのは無しです^^)
## gcc 4.0 ならいけるのかな??

A 回答 (4件)

どうしてもコンパイラを変えたくないなら、他の回答にあるように、返却値を B& にするしかないと思います。

若干補足すると、フリー関数として、

inline B& hoge(B& b)
{
 return b.hoge();
}

inline D& hoge(D& d)
{
 return static_cast<D&>(d.hoge());
}

を作っておけば、多くの問題は解決するかと思います。

ちなみに、gcc-3.4.4ではこの不具合は解決していました。というわけで、gcc-4.0.0でも問題ないと思います。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

No.3 さんのお礼にも記述させてもらいましたが、今回の件は私の単なる勘違いでした。よって、実体化できない クラス B の リファレンスが派生クラスで戻せるなら、とりあえず問題は解決です。

ご提示頂いたアイデアは良いですね。C++ では、ついつい何でも method にしがちですが、クラスに属さない関数を利用したテクニックには私も最近気付き、色々と応用を考え始めたところでした。このアイデアも頂かせてもらいます ^^)

お礼日時:2005/06/27 15:45

> 「ゴメン。

共変はサポートしてないんだ」
> よって、その参照もエラーとなってしまいました。
エラーについてはエラーメッセージを正確に書いて下さい。
そうしないと、誤解が生じて質問者も回答者も損をします。

> 今回の件では class B は抽象クラスのため、実体化できません。
どこで実体化したのですか?
今まで提示されたコードはどこにもBを実体化するようなコードはありません。

> そうですね。でも、面倒というより、無ければ実際に困ってしまいます^^)
covariantが使えないとプログラムが作れないというわけではないと思います。
コンパイラが変えられない以上、簡潔さを多少妥協することをお勧めします。
    • good
    • 0
この回答へのお礼

> エラーについてはエラーメッセージを正確に書いて下さい。
> そうしないと、誤解が生じて質問者も回答者も損をします。
すいません。手元にはそのコンパイラが無かったのと、今回の件はそのエラー自体を主題と思っていなかったため、適当に覚えていた内容を記述してしまいました。

> どこで実体化したのですか?
> 今まで提示されたコードはどこにもBを実体化するようなコードはありません。
あれ!! 当方の勘違いだったようです。

ちょっと間抜けな事に別の部分で実体化できないと出ていたエラーを、この hoge() の部分と思い込んで、実体化できないクラスはその参照も返せないんだと勝手に思っていました。

実体化できないクラスでもその参照は返せるのですね。
と言う事はとりあえず問題解決です。

> covariantが使えないとプログラムが作れないというわけではないと思います。
> コンパイラが変えられない以上、簡潔さを多少妥協することをお勧めします。
確かに仰せのとおりですね。最悪は妥協も考えていましたが、これらのクラスを Template 等で meta programing 的に利用しようとすると、syntax は非常に重要となってしまいます。それで可能な限り突き詰めようと模索していました ^^)

お礼日時:2005/06/27 15:37

class Dの関数hogeを


virtual B& hoge()
{
 return *this;
}
と派生元と合わせ、hogeを呼び出しているほうでキャストしましょう。
D d;
D& hoge = static_cast<D&>(d.hoge());

面倒ですね。
面倒だからこんなキャストをしなくて良いように、covariant(共変?)という機能が追加されたのでしょう。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
そうですね。でも、面倒というより、無ければ実際に困ってしまいます^^)
あまり、困っている人は居ないのかな??

お礼日時:2005/06/25 16:51

ところで共変って何ですか?



今回の場合は、パラメータが一緒で戻り値の型のみが異なるhogeがオーバーロードされたことが原因のはずですが。


クラスBのhogeが純粋仮想関数になっているので、対応方法は
クラスDのメソッドも

B& hoge()

にするのが正しいと思います。
で、使う側がdynamic_castでキャストをする感じかと。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

確かに dynamic_cast を利用するもの一つの方法かと思うのですが、今回の件では class B は抽象クラスのため、実体化できません。よって、その参照もエラーとなってしまいました。

じゃあ hoge() の戻り値を B のポインターにすればよさそうなものですが、そうすると下記の記述ができません。

## 例えば、B に hoge() 以外に B& move(...), B& scaled(...),
## B& rotate(...) 等があったとき、
##
## D d;
## d.move().scaled().rotate();

### ポインターにすると、
### d.move()->scaled()->rotate();
### になりますが、ちょっと美しくありません。

で、共変の許されていない環境では、みなさん一般的にどうされているのかな? と思った次第です。

==
ちなみに共変ですが、英語では covariant と表記されていました。

「C++ 共変」で ググッてみたところ、
http://www2s.biglobe.ne.jp/~ragnarok/program/cpp …
のようなページが見付かりました。

お礼日時:2005/06/25 16:27

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!