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

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

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

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

Q&A

解決済

2回答

2595閲覧

戻り値に自分自身を返すメソッドを持つクラスを継承した時に戻り値の型を適切にしたい

Watching

総合スコア56

C++

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

0グッド

0クリップ

投稿2021/01/28 01:09

題名の通り

c++

1class A { 2protected: 3 A* func() { 4 //メンバを変更する処理 5 return this; 6 } 7}; 8class B :public A { 9 B hoge() { 10 B temp(*this); 11 temp.func(); 12 return temp; 13 }//三行も書かないといけない 14 B moge() { return B(*this).func(); }//こんな感じでローカル変数を作成せずに一行で書きたいが 15 //戻り値がAなので不可 16}

AからBに暗黙キャストできるようにすれば万事解決かと思ったが、ダウンキャストになるのであまりしたくない。
voidも試してみたが、voidからクラスに戻すにはキャストを定義しないといけないが、定義するとどんなポインタでも受け取れてしまうのでこれもあまりしたくない。暗黙キャストを封印すれば解決するが、それはそれで書く量が増えてしまう。また、ポインタは付けたり外したりするのが面倒なのでこういう形で解決するならできれば参照を利用したい。
継承した時に、自動的に型が変わるのが理想だが、不可能ならば、どういう方法が適切か知りたいです。
解答お待ちしております。

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

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

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

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

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

guest

回答2

0

CRTPを使って無理やり戻り値の型を合わせたら?
(Aが普通のクラスじゃなくなるからアップキャストができなくなるけど)

c++

1template<class T> 2class A { 3protected: 4 T& func() { 5 //メンバを変更する処理 6 return static_cast<T&>(*this); 7 } 8}; 9class B :public A<B> { 10public: 11 B moge() { return B(*this).func(); } 12};

投稿2021/01/28 11:46

actorbug

総合スコア2429

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

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

0

ベストアンサー

いまいち何をやりたいのかわからないのですが,こういう話?

C++

1class A 2{ 3public: 4 virtual ~A(){} 5 virtual A* GetThis(){ return this; } 6}; 7 8class B : public A 9{ 10public: 11 virtual B* GetThis() override { return this; } 12 void Test() const { std::cout << "This is B" << std::endl; } 13}; 14 15 16//main 17int main(void) 18{ 19 B b; 20 auto* pb = b.GetThis(); 21 pb->Test(); 22 23 return 0; 24}

できれば参照を利用したい

参照でも同様.

C++

1class A 2{ 3public: 4 virtual ~A(){} 5 virtual A& GetThisRef(){ return *this; } 6}; 7 8class B : public A 9{ 10public: 11 virtual B& GetThisRef() override { return *this; } 12 void Test() const { std::cout << "This is B" << std::endl; } 13}; 14 15//main 16int main(void) 17{ 18 B b; 19 auto &rb = b.GetThisRef(); 20 rb.Test(); 21 22 return 0; 23}

実はこんな話?

C++

1class A 2{ 3protected: 4 //こいつが return this とかすること自体に何の意味もない(ので戻り値を廃止) 5 void func(){ std::cout << "func" << std::endl; } 6}; 7 8class B : public A 9{ 10public: 11 B hoge(){ return B(*this).Call_func_and_Return_Ref(); } 12private: 13 //要は,hoge()を↑のように書けるようにするために,こんなヘルパが欲しいだけの話なのでは? 14 B &Call_func_and_Return_Ref(){ func(); return *this; } 15};

投稿2021/01/28 01:22

編集2021/01/28 04:56
fana

総合スコア11996

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

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

Watching

2021/01/28 04:27 編集

オーバーライドすれば戻り値も変更できるのは初めて知りました。勉強になります。 thisを得ることを目的とするメソッドを作成することが目的ではなく、ある処理をした後にオマケでthisを返すメソッドを作成することが目的です。 継承してオーバーライドすると、同じ処理を二度書くことになってしまうので保守性に問題があります。子クラスで呼び出しても、値を返す時にthisが暗黙的にアップキャストされてしまうので、そうならない方法を探しています。
fana

2021/01/28 04:41

protected なA::func()がthisをreturnしてくる ← まずこれにどれだけの意味があるのか/何が狙いなのか,そこのところが全くわからないので困っています. protected ってことは,A::f()は,Aを継承したクラス(あるいはA自身)が内部実装のために使うメソッドなんですよね? つまり A::f() を呼ぶ場所では単に "this" とさえ書けば手に入るものを,わざわざ A::f() から A* 型のポインタの形で返してもらう理由は何なのでしょう?
fana

2021/01/28 04:54

…という観点で回答を追記しました.
Watching

2021/01/28 04:58

thisのコピーにf()を適用した値を返す関数を作るときに、return B(*this).f();の一行で書けます。 あと、演算子をオーバーロードする時に、二度同じことを書くことを回避したいです。 質問を一般化しすぎてわかりにくかったです。すいません。
Watching

2021/01/28 05:01

例えば+=演算子をオーバーロードするとして、継承元と継承先で挙動が同じで、どちらもthisを返すのに、返り値の型が違うだけで二回記述しなければいけないのでしょうか。
fana

2021/01/28 05:52

> 返り値の型が違う を目指すなら,B側に何か書くのは必要なんじゃないかなぁ. (1) B側でも operator+=( const A& ) という引数型で問題ないならば,この回答で最初に書いたように,仮想関数にしてB側の戻り値を B& とした形で override する. (2) B側では operator+=( const B& ) という引数型にする必要があるならば,Bにこれを実装. この場合,仮想関数ではないことに注意して使う必要がある.
fana

2021/01/28 05:54

(1)と(2) のどちらの場合でも,B側のメソッドの実装は, ・A部分の+=処理のために A::operator+=() を呼び出して, ・最後に return this; と書く 形かと.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問