在 C++ 中使用抽象类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/650091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:30:02  来源:igfitidea点击:

Using an abstract class in C++

c++abstract-classparameters

提问by seanhodges

I'm trying to use an abstract class when passing an extended object as an parameter to a function, but my attempts so far have led to some compiler errors.

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

I have a few clues as to what the problem is, I'm obviously not allowed to instantiate an abstract class, and I believe some of the code in MyClass is trying to do this, even though this is not my intention. Some researching has suggested that I should reference the object as a pointer to achieve what I want, but my attempts so far have failed and I'm not even sure that this is the answer (hence my asking here).

我有一些关于问题所在的线索,我显然不允许实例化抽象类,并且我相信 MyClass 中的一些代码正在尝试这样做,即使这不是我的意图。一些研究建议我应该将对象作为一个指针来引用来实现我想要的东西,但是到目前为止我的尝试都失败了,我什至不确定这就是答案(因此我在这里问)。

I'll submit now that I'm more familiar with Java than C++, and I'm sure part of my problem is due to this.

我现在提交,因为我对 Java 比 C++ 更熟悉,而且我确定我的问题的一部分是由于这个。

Here is an example of what I'm trying to do in my program:

这是我在程序中尝试执行的操作的示例:

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

This example produces the same compiler error that I am getting in my program:

这个例子产生了与我在我的程序中遇到的相同的编译器错误:

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

Update

更新

Thanks for the feedback everyone.

感谢大家的反馈。

I've since changed "MyClass::instance to contain a pointer of type A, but I now get some bizarre errors related to the vtable:

我已经将“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

My modified code is as follows (A and B have not been modified):

我修改后的代码如下(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;
}

回答by Johannes Schaub - litb

Your problem is that you should accept a reference in your function. The reason is that a reference does not actually copy the argument passed. If you however accept an A- instead of a reference A&- then you actually copy the argument passed into the parameter object, and what you get is an object of type A- but which is actually not allowed!

你的问题是你应该在你的函数中接受一个引用。原因是引用实际上并没有复制传递的参数。但是,如果您接受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;
    }

And then you will have to change the member in your class to be a pointer. It can't be a reference because setInstancewill change what it references - a reference can only reference one object during its entire lifetime, while a pointer can be set to point do different things just by reassigning it a different address. The remaining parts look like this then

然后您必须将类中的成员更改为指针。它不能是一个引用,因为setInstance它会改变它引用的内容——一个引用在其整个生命周期中只能引用一个对象,而一个指针可以通过重新分配一个不同的地址来设置为指向做不同的事情。剩下的部分看起来像这样

    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;

Also note that you have to compile C++ programs using g++, because it additionally links the C++ standard library to your code

另请注意,您必须使用 编译 C++ 程序g++,因为它另外将 C++ 标准库链接到您的代码

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

回答by Eric Petroelje

What you are doing would work in Java because declaring a parameter or member variable of type "A" really means a "pointer to an A". In C++, you actually need to be explicit about that since they are two different things:

您正在做的事情在 Java 中可以工作,因为声明“A”类型的参数或成员变量实际上意味着“指向 A”的指针。在 C++ 中,您实际上需要明确说明这一点,因为它们是两种不同的东西:

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

And in the declaration:

并在声明中:

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

回答by Robert S. Barnes

I believe this is what you're trying to do. It demonstrates the polymorphism by actually printing something out depending on whether the handle class points to an instance of B or C. Others are correct that you would probably also want a virtual destructor.

我相信这就是你想要做的。它通过实际打印出一些东西来演示多态性,具体取决于句柄类是指向 B 还是 C 的实例。其他人是正确的,您可能还需要一个虚拟析构函数。

This compiles with: g++ test.cpp -o Test

这编译: 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;
}

回答by Dmitry Khalatov

Your problem now is a linkage. For C++ program, standard C++ library has to be added:

你现在的问题是一个链接。对于 C++ 程序,必须添加标准 C++ 库:

gcc -o test -lstdc++test.cpp

gcc -o test -lstdc++test.cpp

回答by stepancheg

You should store A as a pointer.

您应该将 A 存储为指针。

A* instance;

Edit: I've written "reference" before. There is a difference in C++.

编辑:我之前写过“参考”。在 C++ 中存在差异。

回答by stepancheg

You don't have to use pointersif you resign of the setter and use a constructor. It's one of the important features in C++: base initializers in constructors often allow to avoid using pointers.

如果您放弃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);

回答by Eddy

I had this problem by including parent.hbefore iostream:

我通过包含有这个问题parent.h之前iostream

wrong:

错误的:

include "parent.h"
include <iostream>

right:

对:

include <iostream>
include "parent.h"

回答by ijab

Johannes Schaub - litb is correct.

Johannes Schaub - litb 是正确的。

In C++, Abstract class can't be used as functions' param or return type. We can't instantiate an abstract object.

在 C++ 中,抽象类不能用作函数的参数或返回类型。我们不能实例化一个抽象对象。

So need to use & or *.

所以需要使用&或*。

回答by Aiua

You must use a pointer to A as a member of MyClass.

您必须使用指向 A 的指针作为 MyClass 的成员。

class MyClass {

    public:

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

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

    private:

        A *instance;
};

if you do not do that, MyClass constructor will try to instantiate an A object (as it would for any member object), which is not possible since A is abstract.

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

回答by Aiua

When you say

当你说

A instance;

you will create a new object of type A. But you have already said that A isa an abstract class, so you can't to that. You need to use a pointer, as several otherrs have indicated, or make A non-abstract.

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