C++ 在C+中使用抽象类+;

C++ 在C+中使用抽象类+;,c++,abstract-class,parameters,C++,Abstract Class,Parameters,在将扩展对象作为参数传递给函数时,我尝试使用抽象类,但到目前为止,我的尝试导致了一些编译器错误 关于问题是什么,我有一些线索,我显然不被允许实例化一个抽象类,我相信MyClass中的一些代码正试图这样做,尽管这不是我的意图。一些研究表明,我应该引用对象作为实现我想要的目标的指针,但我的尝试到目前为止都失败了,我甚至不确定这是否是答案(因此我在这里提问) 我现在提交的是我对java的熟悉程度比C++高,我相信我的问题的一部分是由于这个原因。 下面是我在程序中尝试做的一个示例: class A {

在将扩展对象作为参数传递给函数时,我尝试使用抽象类,但到目前为止,我的尝试导致了一些编译器错误

关于问题是什么,我有一些线索,我显然不被允许实例化一个抽象类,我相信MyClass中的一些代码正试图这样做,尽管这不是我的意图。一些研究表明,我应该引用对象作为实现我想要的目标的指针,但我的尝试到目前为止都失败了,我甚至不确定这是否是答案(因此我在这里提问)

我现在提交的是我对java的熟悉程度比C++高,我相信我的问题的一部分是由于这个原因。 下面是我在程序中尝试做的一个示例:

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
此示例产生与我在程序中遇到的编译器错误相同的错误:

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未修改):


你所做的工作在java中是因为声明一个参数或成员变量“a”实际上是一个“指向a的指针”。C++中,你需要明确地指出这一点,因为它们是两个不同的事物:

void setInstance(A* newInstance) { // pointer to an "A"
                instance = newInstance;
}
在宣言中:

A* instance; // Not an actual "A", but a pointer to an "A"

您应该将存储为指针

A* instance;

<>编辑:我以前写过“引用”。C++有不同之处。

你必须使用一个指向MyClass成员的指针。< /P>
class MyClass {

    public:

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

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

    private:

        A *instance;
};
如果您不这样做,MyClass构造函数将尝试实例化一个对象(就像对任何成员对象一样),这是不可能的,因为A是抽象的。

当您说

A instance;

您将创建一个类型为a的新对象。但是您已经说过isa是一个抽象类,所以您不能这样做。您需要使用一个指针,正如其他几个人所指出的那样,或者创建一个非抽象对象。

您的问题是您应该在函数中接受一个引用。原因是引用实际上并没有复制参数通过。但是,如果您接受一个
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
将更改它引用的内容-引用在其整个生命周期中只能引用一个对象,而指针可以设置为点,只需重新为其指定不同的地址即可执行不同的操作。remaining部件看起来像这样

    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++程序,因为它另外将C++标准库链接到代码

g++ -o test test.cpp # instead of gcc!

我相信这就是你要做的。它通过根据句柄类是指向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;
}
#包括
甲级{
公众:
虚空动作()=0;
};
B类:公共A{
公众:
B(){}
无效行动(){
printf(“Hello World\n”);
}
};
C类:公共A类{
公众:
C(){}
无效行动(){
printf(“再见世界”);
}
};
类和类{
公众:
void setInstance(A*A_实例){
APointer=A_实例;
}
无效剂量测定法(){
APointer->action();
}
私人:
A*冬眠;
};
int main(int argc,字符**argv){
阿汉德拉斯阿汉德勒;
B)不确定性;
C.立场;
AHandle.setInstance(&binInstance);
a和doSomething();
AHandle.setInstance(&CInstance);
a和doSomething();
返回0;
}

您现在的问题是链接。 对于C++程序,需要添加标准C++库:


gcc-o test-lstdc++test.cpp

Dmitry是正确的,如果您使用gcc,您应该使用-lstdc++,但更好的是使用
g++


另外,您会注意到(我猜如果您添加了-Wall),您会收到一条警告,说明您的带有虚拟函数的类没有析构函数,因此最好添加一个(虚拟的)析构函数。如果退出setter并使用构造函数,则不必使用指针。这是C++的重要特性之一:构造函数中的基初始值设定项通常允许避免使用指针

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);

我在
iostream
之前包含了
parent.h
,因此出现了这个问题:

错:

include "parent.h"
include <iostream>
包括“parent.h”
包括
对:

include <iostream>
include "parent.h"
包括
包括“parent.h”

约翰内斯·肖布-利特是正确的

<>在C++中,抽象类不能用作函数的PARAM或返回类型。我们不能实例化一个抽象对象。
所以需要使用&或*

这不是一个引用,而是一个指针。请编辑您的答案。您所解释的是有意义的,但因为我声明了“实例”“作为指针,我得到与vtable相关的链接器错误。。。我将更新我的问题以对此进行扩展。@n0rd-我的错,我本来打算使用引用,但在注意到他的声明不能用作引用(refs不能为null)后,我切换到了指针。我将编辑并修复它。感谢您发布这篇文章,我尝试编译它,它产生了与我当前在更新代码中得到的相同的vtable错误。有什么想法吗?最后我不小心用了->当我应该用的时候。它现在可以编译了,我添加了一些东西使它更具信息性。这很有效,因为它位于主界面上,但在其他情况下,如果
a句柄
超出了
b实例
c实例
都声明为