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

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

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

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

C++

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

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

2回答

2110閲覧

【C++】継承したクラス関数について【rust】

ddp

総合スコア17

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

C++

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

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0グッド

0クリップ

投稿2020/09/18 15:09

C++もRUSTも初心者です。休日プログラマーなので頼れる方もおらず、
どなたかご教授ください。

以下のコードでは、HOGEクラスで定義したhoge関数を、AAA&BBBクラスに継承している単純なコードなのですが・・・

c++

1#include <string> 2 3class HOGE{ 4public: 5 void hoge(unsigned short ccc); 6}; 7 8void HOGE::hoge(unsigned short ccc){ 9 printf("VALUE = %d\n", ccc); 10} 11 12 13class AAA : public HOGE{ 14public: 15 unsigned short aaa; 16}; 17 18class BBB : public HOGE{ 19public: 20 unsigned short bbb; 21}; 22 23 24 25int main(){ 26 27 AAA obj; 28 29 obj.aaa = 10000; 30 obj.hoge(obj.aaa); 31 32 BBB obj2; 33 34 obj2.bbb = 20000; 35 obj2.hoge(obj2.bbb); 36} 37 38//実行結果 39VALUE = 10000 40VALUE = 20000 41

この継承されるhoge関数の内容自体をAAAクラス、BBBクラスで異なる内容にしたい、かつ宣言はHOGEクラスにて行いたい場合には
どのように記述したらよいでしょうか。
イメージとしてはRUSTのpub trait HOGE内の関数を「impl HOGE for AAA」のように使用する場合と同じ記述をc++でしたいです。

拙い説明で恐縮ですが、よろしくお願いいたします。

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

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

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

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

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

guest

回答2

0

結論から言えば出来ません。 継承やその他の宣言で特定のインターフェイスを満たしていることを表明する直接的な方法は用意されていません。

C++ の仮想関数 (virtual) を使った定義はわかりやすいのですがそれは Rust で言うところの dyn のようなもので実行時のポリモーフィズムを実現する機能です。 トレイトに dyn を付けるだけで動的なポリモーフィズムが出来る Rust はうらやましいですね。

あえていうなら必要なメンバを持っているかどうかを判定するメタ関数を作り static_assert で検査するという方法は考えられます。

cpp

1#include <type_traits> 2#include <iostream> 3 4template<class T> 5class has_hoge { 6 template<class U, void (U::*)(unsigned short)> 7 struct helper_t { typedef T type; }; 8 9 template<class U, class V = T> 10 struct helper : std::false_type {}; 11 12 template<class U> 13 struct helper<U, typename helper_t<U, &U::hoge>::type> : std::true_type {}; 14 15public: 16 static const bool value = helper<T>::value; 17}; 18 19class AAA { 20public: 21 unsigned short aaa; 22 void hoge(unsigned short ccc){ 23 std::cout << "VALUE = " << ccc << std::endl; 24 } 25}; 26 27static_assert(has_hoge<AAA>::value, "AAA has not hoge"); 28 29class BBB { 30public: 31 unsigned short bbb; 32 void hoge(unsigned short ccc) { 33 std::cout << "VALUE = " << ccc << std::endl; 34 } 35}; 36 37static_assert(has_hoge<BBB>::value, "BBB has not hoge"); 38 39int main(){ 40 41 AAA obj; 42 43 obj.aaa = 10000; 44 obj.hoge(obj.aaa); 45 46 BBB obj2; 47 48 obj2.bbb = 20000; 49 obj2.hoge(obj2.bbb); 50}

ただ、メタ関数の作り方はテンプレートの特殊化の規則をよく理解しないと作れません。 初心者が上の例をいくら眺めても理解不能でしょう。

最新の C++ (C++20) では型の制約を直接的に表現できる concept と呼ばれる機能が登場しましたが、 Rust の impl とは全く違います。

投稿2020/09/18 19:39

SaitoAtsushi

総合スコア5684

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

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

ddp

2020/09/19 11:49

返信おそくなりました。 static_assertというものを初めて知りました。これは別途活用していきたいと思います。ありがとうございます。 私のrustに関する知識も相当拙劣なので、そもそもimpl HOGE for hogeが「特定のインターフェイスを満たしていることを表明する」検証機能を備えていること自体知りませんでした。 私が満たしたい内容としては、とあるクラスで宣言してある関数をそのほかのクラスで別々に実装できれば良いと考えているので、virtualで問題ないと考えていますがどうでしょうか。
SaitoAtsushi

2020/09/19 16:45

繰り返しますが virtual は呼び出すべき関数を実行時に選択する仕組みです。 抽象クラスの継承は結果的に特定のインターフェイスを強制することも含まれるとはいうものの、実行時ポリモーフィズムを活用しないときに実行時ポリモーフィズムのための言語機能を使うということを問題ないと考えるのは一般的ではないでしょうね。 mitama_rs さんのコードがわざわざ invoke_hoge を経由しているのは、実行時ポリモーフィズムのための言語機能を使うから実行時ポリモーフィズムが活用される形で例を示しているのです。 そうする必要がないのであれば抽象クラスを使うべきではありません。
ddp

2020/09/24 03:54

正直なところ、抽象クラスを使うべきか(多相化する必要があるのか)よくわからなくなってきました。 ご丁寧に説明頂きありがとうございます。 もう少し自身で勉強してみます。
SaitoAtsushi

2020/09/24 08:09

ちょっと説明が不足していたので補足。 私が「実行時」という言葉を省略せずに書いているのは、逆に言えば実行時ではない多相があるということです。 多相には大きくわけて実行時のものとコンパイル時のものがあるということを意識してください。 (単にポリモーフィズムと言ったときにどちらかだけのことを指しているような資料もあるので注意を要するのですが。) 抽象クラスは実行時の多相を実現するもので、コンパイル時の多相はテンプレートでおこなうというのが C++ での役割分担です。 (Rust だとどちらもトレイトでやってしまえるようになっています。)
ddp

2020/09/25 09:12

>>抽象クラスは実行時の多相を実現するもので、コンパイル時の多相はテンプレートでおこなうというのが C++ での役割分担です。 ・・の部分について、今の私には正直よくわかりません。 一つお聞きしたいのですが、ポリモーフィズム、多相化のメリットというのは何処にあるのでしょうか? mitama_rsさんの例にあるinvoke_hogeについても、それぞれobj.hoge()、obj2.hoge()とすれば良いと思えてしまうのですが・・。 お時間ありましたらご返答ください。
SaitoAtsushi

2020/09/25 09:33

invoke_hoge に意味が見いだせないという理解は逆です。 invoke_hoge のようなものが必要になったときに多相が必要になるという説明なのです。 obj.hoge() 、 obj2.hoge() とすればよいときはそれでよいです。 そしてそのときには多相も不要です。
guest

0

ベストアンサー

C++では、つぎのように書きます。

cpp

1#include <iostream> 2class HOGE{ 3public: 4 virtual void hoge(unsigned short ccc) const = 0; 5}; 6 7class AAA : public HOGE{ 8public: 9 void hoge(unsigned short ccc) const override { 10 printf("AAA: VALUE = %d\n", ccc); 11 } 12}; 13 14class BBB : public HOGE{ 15public: 16 void hoge(unsigned short ccc) const override { 17 printf("BBB: VALUE = %d\n", ccc); 18 } 19}; 20 21void invoke_hoge(HOGE const& hoge, unsigned short v) { hoge.hoge(v); } 22 23int main(){ 24 25 AAA obj; 26 27 invoke_hoge(obj, 10000); // AAA: VALUE = 10000 28 29 BBB obj2; 30 31 invoke_hoge(obj2, 20000); // BBB: VALUE = 20000 32}

まず、基底クラスHOGEでvirtual void hoge(unsigned short ccc) const = 0;と宣言します。
これはpure virtual functionというもので、実装をもちません。

AAA、BBBではHOGEを継承し、仮想関数hogeをオーバーライドします。
基底クラスの仮想関数と同じシグネチャの関数を書くとオーバーライドされます。
Rustのimplのような専用の文法はありません。

このAAAやBBBの変数をHOGEの参照(もしくはポインタ)として渡すと、hoge(...)の呼び出しはオーバーライドされたものが呼び出されます。

投稿2020/09/18 16:02

mitama_rs

総合スコア165

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

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

ddp

2020/09/19 11:27

返信遅くなりました。 pure virtual functionというもの自体知りませんでした。 こちらで確かに用件を満たせそうですが、中断のinvoke_hoge関数はどういった意味がありますか? ネットで純粋仮想関数について調べたところ、以下のリンクに行き着きまして、 https://kaworu.jpn.org/cpp/%E7%B4%94%E7%B2%8B%E4%BB%AE%E6%83%B3%E9%96%A2%E6%95%B0 invoke_hogeのような記述はなく、たしかになくても実装できそうな気がしています。 何かテクニックが潜んでいそうなのでご面倒でなければ解説をお願いできないでしょうか。 よろしくお願いします。
mitama_rs

2020/09/19 13:33

`AAA obj; obj.hoge(10000);` だと、ただAAAのメンバ関数を呼び出しているだけです。 なんの多相性もありません。 ですので、HOGEとして受け取ってhoge関数を呼び出すために例としてinvoke_hogeを経由させています。
ddp

2020/09/24 03:52

了解しました。 たしかに多相性は無いように思われます。 ご丁寧にご説明頂きありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問