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

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

新規登録して質問してみよう
ただいま回答率
87.20%
継承

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

C++

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

Julia

Juliaとは、科学技術計算に特化した、高水準・高性能な動的プログラミング言語です。オープンソースとして公表されており、書き易く動きが早いことが特徴です。

受付中

C++ で多重ディスパッチをする方法と Julia 2

Paalon
Paalon

総合スコア0

継承

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

C++

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

Julia

Juliaとは、科学技術計算に特化した、高水準・高性能な動的プログラミング言語です。オープンソースとして公表されており、書き易く動きが早いことが特徴です。

2回答

0評価

0クリップ

1738閲覧

投稿2020/03/20 18:43

編集2022/01/12 10:55

前の質問は こちら です。文字数上限に達してしまったため、続きをここに記述します。

追記3

色々理解が整理できたので質問し直します。C++ ではメンバ関数として仮想関数を実装すれば、例えば、次のように

cpp

#include <iostream> #include <vector> #include <memory> struct Animal { virtual ~Animal() = 0; virtual void printlntype() { std::cout << "Animal" << std::endl; } }; Animal::~Animal() {} struct Dog final : Animal { void printlntype() override { std::cout << "Dog" << std::endl; } }; struct Cat final : Animal { // void printlntype() override { // std::cout << "Cat" << std::endl; // } }; int main() { auto dog = Dog(); auto cat = Cat(); dog.printlntype(); cat.printlntype(); auto animals = std::vector<std::shared_ptr<Animal>>{ std::make_shared<Dog>(), std::make_shared<Cat>() }; for (auto const & animal: animals) { animal->printlntype(); } }

スーパー型 Animal のポインタとして呼び出された関数はもともと?部分型 Dog だったときオーバーロードされるので、1変数(クラスについての)部分型ポリモルフィズムができ、配列などそのポリモルフィズムを実現できることは分かります。

多変数で部分型ポリモルフィズムを考えるときには、(1変数での実装しかできない)メンバ関数のポリモルフィズムを使うわけにはいかないので、普通の関数として実装することになります。以下のように実装すれば(Animal 型を継承する全ての型を入れた std::variant 的なものが自動で作れるのかどうかを除いて)、

cpp

/* g++-HEAD -std=c++2a multiple_dispatch.cpp ./a.out */ #include <concepts> #include <iostream> #include <vector> #include <variant> #include <memory> struct Animal { virtual ~Animal() = 0; }; Animal::~Animal() {} struct Dog final : Animal {}; struct Cat final : Animal {}; using SubAnimal = std::variant<Dog, Cat>; // one variable template <std::derived_from<Animal> T> auto printlntype(T const &) { std::cout << "Animal" << std::endl; } auto printlntype(Dog const &) { std::cout << "Dog" << std::endl; } // auto printtype(Cat const &) { // std::cout << "Cat" << std::endl; // } // two variables template <std::derived_from<Animal> T> auto printlntype(T const &, T const &) { std::cout << "Animal Animal" << std::endl; } template <std::derived_from<Animal> T> auto printlntype(Dog const &, T const &) { std::cout << "Dog Animal" << std::endl; } template <std::derived_from<Animal> T> auto printlntype(T const &, Dog const &) { std::cout << "Animal Dog" << std::endl; } auto printlntype(Dog const &, Dog const &) { std::cout << "Dog Dog" << std::endl; } int main() { auto dog = Dog(); auto cat = Cat(); // single dispatch printlntype(dog); printlntype(cat); // double dispatch printlntype(dog, dog); printlntype(dog, cat); printlntype(cat, dog); printlntype(cat, cat); auto animals = std::vector<std::shared_ptr<std::variant<Dog, Cat>>>{ std::make_shared<SubAnimal>(SubAnimal(Dog())), std::make_shared<SubAnimal>(SubAnimal(Cat())) }; // single dispatch for (auto const & animal: animals) { std::visit( [] (const auto & x) { printlntype(x); }, *animal ); } // double dispatch for (auto const & v_animal1: animals) { for (auto const & v_animal2: animals) { std::visit( [&] (const auto & animal1) { std::visit( [&] (const auto & animal2) { printlntype(animal1, animal2); }, *v_animal2 ); }, *v_animal1 ); } } }

実行結果は

txt

Dog Animal Dog Dog Dog Animal Animal Dog Animal Animal Dog Animal Dog Dog Dog Animal Animal Dog Animal Animal

となり、多変数部分型ポリモルフィズム、つまりマルチディスパッチが実現できると思います。Julia の文章が言いたいことというのは、

  1. 一般的に C++ で想定されている部分型ポリモルフィズムの実現方法がメンバ関数としてのシングルディスパッチであり、それではマルチディスパッチは実現できないということ。
  2. C++ でマルチディスパッチを実現しようとすればできるが、パラメトリックポリモルフィズムが絡んだとき、つまり、配列などのコンテナの要素の型に関して部分型ポリモルフィズムをするときには、std::variant を使ったようなコードを書く必要があり、そのあたりのコードがパフォーマンス的によろしくない、もしくは自動的に subtyping された std::variant 的なものが作れないためにコードが煩雑であり、現実的でない?どちらにせよ、あまり一般的に(まだ?)使われていない。

ということなんでしょうか?

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

izmktr
izmktr

2020/03/20 19:24

もしかしたら私の勘違いかもしれませんが、 auto dog = Dog() と auto dog = new Dog() と Animal *dog = new Dog() の違いが問題になる話じゃないでしょうか? 本来書かないといけないサンプルは後ろの2個のどちらかのように思います

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

継承

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

C++

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

Julia

Juliaとは、科学技術計算に特化した、高水準・高性能な動的プログラミング言語です。オープンソースとして公表されており、書き易く動きが早いことが特徴です。