10

友人の1人が、「C ++でランタイムポリモーフィズムを実現するにはどうすればよいですか?」と尋ねました。私は「継承によって」と答えました

「いいえ、仮想関数を使用してのみ実現できます」と彼は言いました。

だから私は彼に次のコードの例を与えました:-

#include<iostream>
using namespace std;

class A
{
public:
    int i;
    A(){i=100;}
};

class B : public A
{
public:
    int j;
    B(){i = -1; j = 99;}
};

void func(A& myA)
{
    cout<<myA.i << endl;
}

int main()
{
    B b;
    A* a = new B();
    func(*a);
    func(b);
    delete a;
    return 0;
}

ここで、関数func()はAを参照しますが、Bのオブジェクトを渡し、パブリックメンバー「i」の値を出力できます。彼はそれがコンパイル時のポリモーフィズムだと言った。

私の質問は:-

1)ランタイムポリモーフィズムは仮想関数でのみ実現されますか?

2)上記の例には、実行時のポリモーフィズムまたはコンパイル時間がありますか?

3)次のコードがある場合:-

void func2(A& myA)
{
    cout << myA.i << endl;
    // dynamic/static cast myA to myB
    cout<<myB.j << endl;
}

どんなポリモーフィズムですか?それともポリモーフィズムですか?

4

6 に答える 6

9

この例では、動的ポリモーフィズムは示されていません。呼び出されるメソッドは、コンパイル時に認識されます。どのメソッドを呼び出す必要があるかについて、(実際のオブジェクト タイプに基づく)実行時の決定はありません。タイプが異なっても異なる動作はありません。

この例は、動的ポリモーフィズムの例です。基本クラスでメンバー関数を提供し、派生クラスでそれをオーバーライド
する必要があります。virtual呼び出される実際のメソッドは、基本クラス ポインターが指すオブジェクトの実際の型によって決まります。

オンラインサンプル

#include<iostream>
using namespace std;

class A
{
public:
    virtual void doSomething()
    {
        std::cout<<"\nIn A::doSomething()";
    }
};

class B : public A
{
public:
    virtual void doSomething()
    {
        std::cout<<"\nIn B::doSomething()";
    }
};



int main()
{
    B b;
    A obj;
    A* a = &b;
    a->doSomething();

    a = &obj;
    a->doSomething();

    return 0;
}

出力:

In B::doSomething()
In A::doSomething()

ランタイム ポリモーフィズムは仮想関数でのみ達成されますか?

いいえ、しかしvirtual関数はそうするための最も一般的で正しい方法です。
ポリモーフィズムは、関数ポインターを介して実現できます。次のコード例を考えてみましょう。実際に呼び出すメソッドは、ユーザー入力に応じて実行時に決定されます。これは、厳密には C++ の意味ではなく、異なるに対して異なる動作を要求するポリモーフィズムの形式です。

#include <iostream>

typedef void (*someFunction)(int, char*);

void FirstsomeFunction(int i, char *c)
{
    std::cout<<"\n In FirstsomeFunction";
}

void SecondsomeFunction(int i, char *c)
{
    std::cout<<"\n In SecondsomeFunction";
}

int main()
{
    someFunction arr[1];
    int x = 0;
    std::cin >> x;

    if(x ==0)
        arr[0] = &FirstsomeFunction;
    else
        arr[0] = &SecondsomeFunction;

    (arr[0])(10,"Hello");

    return 0;
}

上記の例には、ランタイム ポリモーフィズムまたはコンパイル時間がありますか?

いかなる種類のポリモーフィズムもありません。すべての場合で同じメソッドが呼び出されます。異なる型に対して異なる動作はないため、いかなる種類のポリモーフィズムにも分類されません。

于 2013-02-19T08:51:13.737 に答える
7

C言語はfprintf多態的な関数です。

さまざまなハンドルを渡すことができ、ファイル、stdout、プリンター、ソケットなど、システムがストリームとして表現できるものなら何でも出力できます。

FILE* file = fopen("output.txt", "w");                    // a file
FILE* file = stdout;                                      // standard output
FILE* file = fopen("/dev/usb/lp0", "w");                  // a usb printer
FILE* file = popen("/usr/bin/lpr -P PDF", "w");           // a PDF file
FILE* file = fdopen(socket(AF_INET,SOCK_STREAM,0), "r+"); // network socket

fprintf(file, "Hello World.\n");
于 2013-02-19T09:01:20.980 に答える
2

あなたが書いたものはポリモーフィズムではありません。

これは、C++ でポリモーフィズムを行う方法です。

#include<iostream>
using namespace std;

class A
{
public:
    virtual void func(){
        cout << "printing A" << endl;
    }

    virtual ~A(){}
};

class B : public A
{
public:
    void func(){
        cout << "printing B" << endl;
    }
};

int main()
{
    A* a = new A();
    A* b = new B();

    a->func(); // "printing A"
    b->func(); // "printing B"

    delete a;
    delete b;

    return 0;
}

virtual キーワードを削除するとfunc、A のメソッドが 2 回呼び出されます。

于 2013-02-19T08:57:42.530 に答える
1

友人の1人が、「C ++でランタイムポリモーフィズムを実現するにはどうすればよいですか?」と尋ねました。私は「継承によって」と答えました。彼は「いいえ、仮想関数を使用することによってのみ達成できます」と述べました。

まず、ポリモーフィズムという用語はあいまいです。一般的なコンピューティングサイエンスの意味では、コンパイル時か実行時かに関係なく、タイプ固有のコードを暗黙的に呼び出す機能を指します。C ++標準では、非常に狭く定義されており、仮想ディスパッチです(これは標準の浸透です)。明らかに、友人の質問が意味のあるものになるためには、彼がC ++でどのように達成されるかを尋ねているので、彼の視点はC++の外部からでなければなりません-コンピューティングサイエンスの用語のより大きな文脈で。

確かに、仮想関数/ディスパッチは答えですが、それが唯一の答えですか...?

これに答えるには、実行時のポリモーフィックとしてどのような動作が適格であるかを明確に理解することが役立ちます。検討:

void f(X& x)
{
    // the only situation where C++ doesn't know the run-time type of a variable is
    // where it's an instance of a class/struct accepted by reference or pointer

    ...some operation involving "x"...
}

実行時タイプの「x」に特に関連する理由で、「x」を含む操作に対して異なるマシンコードが呼び出される可能性のあるメカニズムは、実行時ポリモーフィックにかなり近づいていますが、最後の問題が1つあります。 :その分岐は言語によって暗黙的に決定されたのですか、それともプログラマーによって明示的に配置されたのですか?

仮想ディスパッチの場合、コンパイラは、タイプに適したコードに分岐する仮想ディスパッチテーブルとルックアップを作成することを暗黙的に認識しています。

ただし、以前にタイプ固有のコードをアドレス指定するように設定された関数ポインター、またはタイプ固有のを制御するために使用されるタイプ固有の数値または列挙switch型があるとしcaseます。これらは機能的に実行時仮想ディスパッチと同じ動作を実現しますが、セットアップは開発者が明示的に行う必要があり、決定が純粋に実行時型で行われることを確認するコンパイラの強制はありません。彼らが資格を得るかどうかは議論の余地があります。C ++には仮想ディスパッチの完全な暗黙のメカニズムがあり、C ++標準では、特に仮想ディスパッチに関連する定義が狭められているため、ほとんどのC++プログラマーは「いいえ」と言うでしょう。

しかし、Cの世界では、sayqsortまたはbsearch(関数ポインター引数を介した実行時ディスパッチを使用して任意の型を処理する2つの標準libC関数)を実行時ポリモーフィックとして説明すると、すぐに理解できる場合があります...ただし、一般的な実装。

それでも、実行時のポリモーフィズムの機能定義が記載されたコンピューティングサイエンスの教科書は間違いなく何百もあり、関数ポインターまたは他のプログラマーが初期化したメタデータを使用してディスパッチすることで、かなりの割合を満たしているに違いありません。したがって、明確な答えが1つしかないことを主張しすぎるのは無意味です。

私の質問は:-

1)ランタイムポリモーフィズムは仮想関数でのみ実現されますか?

上記のように、私はC ++のコンテキストでは「はい」に傾倒しますが、それは(際限なく)議論の余地があります。

2)上記の例には、実行時のポリモーフィズムまたはコンパイル時間がありますか?

どちらでもありません...タイプに基づいて選択する2つの関数さえありません-func()タイプがであるという期待を与えられてコンパイラによって選択された:に対して常に同じマシンコードを実行していますA

3)次のコードがある場合:-

void func2(A& myA)
{
    cout << myA.i << endl;
    // dynamic/static cast myA to myB
    cout<<myB.j << endl;
}

どんなポリモーフィズムですか?それともポリモーフィズムですか?

タイプに基づく分岐がないため、ポリモーフィックではありません。動的キャストは、実行時型myAのコンパイラー入力型メタデータを参照できます。これを使用して、へのアクセスのみを条件付きで呼び出す場合は、 -myB.jでない限り未定義の動作になります-に戻ります。手動で、明示的に開発者が調整したタイプ固有の動作、およびそれが「ポリモーフィズム」として適格かどうかについては、上記で説明しました。myAB

于 2013-02-19T10:52:23.273 に答える
0

【C++】

ポリモーフィズムは、アクションの一般的なクラスへのアクセスを制御する 1 つのインターフェイスとして定義されます。ポリモーフィズムには、コンパイル時ポリモーフィズムと実行時ポリモーフィズムの 2 種類があります。コンパイル時のポリモーフィズムは、関数と演算子のオーバーロードです。ランタイム ポリモーフィズムは、継承と仮想関数を使用して行われます。

ポリモーフィズムとは、関数が異なる時点で異なる形式を取ることを意味します。コンパイル時の場合は、関数のオーバーロードと呼ばれます。たとえば、プログラムは 2 つの関数で構成され、1 つは整数の加算を実行でき、もう 1 つは浮動小数点数の加算を実行できますが、関数の名前は add のように同じにすることができます。関数 add() はオーバーロードされていると言われています。2 つ以上の関数に同じ名前を付けることができますが、それらのパラメーター リストは、パラメーターまたはデータ型の点で異なる必要があります。戻り値の型だけが異なる関数はオーバーロードできません。コンパイラは、渡されたパラメータのタイプに応じて適切な関数を選択します。クラスの場合、初期化されたオブジェクトと初期化されていないオブジェクトの両方が存在する可能性があるため、コンストラクターがオーバーロードされる可能性があります。

于 2013-02-19T10:47:37.390 に答える
0

ポリモーフィズムは、仮想関数によって実現されます。ただし、効果を得るには、つまり、型に応じて異なる動作を行うには、継承も必要です

struct A {
    virtual void f() = 0;
};

struct B : public A {
    void f() {
        // do B things
        std::cout << "B::f() called\n";
    }
};

struct C : public A {
    void f() {
        // do C things
        std::cout << "C::f() called\n";
    }
};

Aこれで、 か かによって、異なる動作で へのポインタまたは参照を持つことができBますC

于 2013-02-19T08:56:44.057 に答える