16

拡張オブジェクトをパラメーターとして関数に渡すときに抽象クラスを使用しようとしていますが、これまでの試行でいくつかのコンパイラ エラーが発生しました。

問題が何であるかについていくつかの手がかりがあります.抽象クラスをインスタンス化することは明らかに許可されていません.MyClassのコードの一部はこれを実行しようとしていると思いますが、これは私の意図ではありません. いくつかの調査では、目的を達成するためにオブジェクトをポインターとして参照する必要があることが示唆されていますが、これまでの試みは失敗しており、これが答えであるかどうかさえわかりません (したがって、ここで質問しています)。

私は C++ よりも Java に精通しているので、提出します。私の問題の一部はこれによるものだと確信しています。

これが私のプログラムでやろうとしていることの例です:

class A {
    public:
        virtual void action() = 0;
};

class B : public A {
    public:
        B() {}

        void action() {
            // Do stuff
        }
};

class MyClass {

    public:

        void setInstance(A newInstance) {
            instance = newInstance;
        }

        void doSomething() {
            instance.action();
        }

    private:

        A instance;
};

int main(int argc, char** argv) {
    MyClass c;
    B myInstance;
    c.setInstance(myInstance);
    c.doSomething();
    return 0;
}

この例では、プログラムで発生したのと同じコンパイラ エラーが発生します。

sean@SEAN-PC:~/Desktop$ gcc -o test test.cpp
test.cpp:20: error: cannot declare parameter ‘newInstance’ to be of abstract type ‘A’
test.cpp:2: note:   because the following virtual functions are pure within ‘A’:
test.cpp:4: note:   virtual void A::action()
test.cpp:30: error: cannot declare field ‘MyClass::instance’ to be of abstract type ‘A’
test.cpp:2: note:   since type ‘A’ has pure virtual functions
test.cpp: In function ‘int main(int, char**)’:
test.cpp:36: error: cannot allocate an object of abstract type ‘A’
test.cpp:2: note:   since type ‘A’ has pure virtual functions

アップデート

フィードバックありがとうございます。

「MyClass::instance」を A 型のポインターを含むように変更しましたが、vtable に関連するいくつかの奇妙なエラーが発生するようになりました。

sean@SEAN-PC:~/Desktop$ gcc -o test test.cpp
/tmp/ccoEdRxq.o:(.rodata._ZTI1B[typeinfo for B]+0x0): undefined reference to `vtable for __cxxabiv1::__si_class_type_info'
/tmp/ccoEdRxq.o:(.rodata._ZTI1A[typeinfo for A]+0x0): undefined reference to `vtable for __cxxabiv1::__class_type_info'
/tmp/ccoEdRxq.o:(.rodata._ZTV1A[vtable for A]+0x8): undefined reference to `__cxa_pure_virtual'
collect2: ld returned 1 exit status

私の変更されたコードは次のとおりです (A と B は変更されていません)。

class MyClass {

    public:

        void setInstance(A* newInstance) {
            instance = newInstance;
        }

        void doSomething() {
            instance->action();
        }

    private:

        A* instance;
};

int main(int argc, char** argv) {
    MyClass c;
    B myInstance;
    c.setInstance(&myInstance);
    c.doSomething();
    return 0;
}
4

11 に答える 11

27

あなたの問題は、関数で参照を受け入れる必要があることです。その理由は、参照は渡された引数を実際にはコピーしないためです。Aただし、参照の代わりに - を受け入れると、A&実際にはパラメーター オブジェクトに渡された引数をコピーし、取得するのは型のオブジェクトですAが、これは実際には許可されていません!

    // the reference parameter will reference the actual argument
    void setInstance(A &newInstance) {
            // assign the address of the argument to the pointer member
            // instance. 
            instance = &newInstance;
    }

次に、クラスのメンバーをポインターに変更する必要があります。参照するものを変更するため、参照にすることはできません。参照setInstanceは、その存続期間全体で1つのオブジェクトのみを参照できますが、ポインターは、別のアドレスを再割り当てするだけで別のことを行うように設定できます。残りのパーツはこんな感じ

    void doSomething() {
        // call a member function on the object pointed to
        // by instance!
        instance->action();
    }

private:

    // a pointer to some object derived from A
    A *instance;

g++また、C++ 標準ライブラリをコードに追加でリンクするため、を使用して C++ プログラムをコンパイルする必要があることにも注意してください。

g++ -o test test.cpp # instead of gcc!
于 2009-03-16T12:07:37.030 に答える
5

タイプ「A」のパラメーターまたはメンバー変数を宣言することは、実際には「Aへのポインター」を意味するため、あなたがしていることはJavaで機能します。C++ では、これらは 2 つの異なるものであるため、実際にはそれについて明示する必要があります。

void setInstance(A* newInstance) { // pointer to an "A"
                instance = newInstance;
}

そして宣言では:

A* instance; // Not an actual "A", but a pointer to an "A"
于 2009-03-16T12:00:00.763 に答える
3

これがあなたがやろうとしていることだと思います。ハンドル クラスが B と C のどちらのインスタンスを指しているかに応じて、実際に何かを出力することにより、ポリモーフィズムを示しています。仮想デストラクタも必要になる可能性が高いという意見もあります。

これは次のようにコンパイルされます: g++ test.cpp -o Test

#include <stdio.h>

class A {
    public:
        virtual void action() = 0;
};

class B : public A {
    public:
        B() {}

        void action() {
                printf("Hello World\n");
        }
};

class C : public A {
    public:
        C() {}

        void action() {
                printf("Goodbye World\n");
        }
};

class AHandleClass {

    public:

        void setInstance(A *A_Instance) {
                APointer = A_Instance;
        }

        void doSomething() {
                APointer->action();
        }

    private:

        A *APointer;
};

int main(int argc, char** argv) {
    AHandleClass AHandle;
    B BInstance;
    C CInstance;
    AHandle.setInstance(&BInstance);
    AHandle.doSomething();
    AHandle.setInstance(&CInstance);
    AHandle.doSomething();
    return 0;
}
于 2009-03-16T12:11:44.463 に答える
3

あなたの問題は今リンケージです。C++ プログラムの場合、標準 C++ ライブラリを追加する必要があります。

gcc -o test -lstdc++ test.cpp

于 2009-03-16T12:32:20.763 に答える
1

A をポインタとして格納する必要があります。

A* instance;

編集:以前に「参照」を書きました。C++ には違いがあります。

于 2009-03-16T12:00:11.853 に答える
1

セッターを辞任してコンストラクターを使用する場合は、ポインターを使用する必要はありません。これは C++ の重要な機能の 1 つです。コンストラクターの基本初期化子により、多くの場合、ポインターの使用を回避できます。

class MyClass {

        public:

                MyClass(A & newInstance) : instance(newInstance) {
                }

                void doSomething() {
                        instance.action();
                }

        private:

                A & instance;
};



int main(int argc, char** argv) {
        B myInstance;
        MyClass c(myInstance);
于 2009-03-17T10:20:37.263 に答える
1

parent.hbeforeを含めることでこの問題が発生しましたiostream

違う:

include "parent.h"
include <iostream>

右:

include <iostream>
include "parent.h"
于 2010-12-20T13:14:22.570 に答える
1

Johannes Schaub - litb は正しいです。

C++ では、Abstract クラスを関数のパラメーターまたは戻り値の型として使用できません。抽象オブジェクトをインスタンス化することはできません。

したがって、& または * を使用する必要があります。

于 2012-11-23T07:04:55.910 に答える
0

A へのポインターを MyClass のメンバーとして使用する必要があります。

class MyClass {

    public:

        void setInstance(A *newInstance) {
                instance = newInstance;
        }

        void doSomething() {
                instance->action();
        }

    private:

        A *instance;
};

そうしないと、MyClass コンストラクターは (メンバー オブジェクトの場合と同様に) A オブジェクトをインスタンス化しようとしますが、A は抽象的であるため、これは不可能です。

于 2009-03-16T12:02:22.833 に答える
0

あなたが言う時

A instance;

タイプ A の新しいオブジェクトを作成します。しかし、A は抽象クラスであるとすでに述べているので、それはできません。他のいくつかの人が示しているように、ポインターを使用するか、 A を非抽象にする必要があります。

于 2009-03-16T12:05:29.877 に答える
0

Dmitry は正しいです。gcc を使用する場合は -lstdc++ を使用する必要がありますが、g++代わりに使用することをお勧めします。(同じ構文)。
また、仮想関数を持つクラスにはデストラクタがないという警告が表示されることに注意してください (-Wall を追加すると思います)。したがって、A にも (仮想) デストラクタを追加することをお勧めします。

于 2009-03-16T12:37:01.437 に答える