在c++中使用抽象类。

时间:2022-09-02 00:09:04

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

11 个解决方案

#1


27  

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 setInstance will 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

还要注意,您必须使用g++编译c++程序,因为它还将c++标准库链接到您的代码中。

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

#2


5  

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"

#3


3  

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

你现在的问题是联系。对于c++程序,必须添加标准c++库:

gcc -o test -lstdc++ test.cpp

测试-lstdc++ test.cpp。

#4


3  

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++测试。cpp - o测试

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

#5


1  

You should store A as a pointer.

您应该将A存储为指针。

A* instance;

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

编辑:我以前写过“参考”。在c++中有一个区别。

#6


1  

You don't have to use pointers if 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);

#7


1  

I had this problem by including parent.h before iostream:

我有个问题,包括父母。h iostream之前:

wrong:

错误的:

include "parent.h"
include <iostream>

right:

正确的:

include <iostream>
include "parent.h"

#8


1  

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++中,抽象类不能用作函数的param或返回类型。我们不能实例化一个抽象对象。

So need to use & or *.

所以需要使用&或*。

#9


0  

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

您必须使用一个指针作为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是抽象的。

#10


0  

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类型的新对象,但是您已经说过,isa是一个抽象类,所以您不能这样做。您需要使用一个指针,就像其他几个人指出的那样,或者做一个非抽象的。

#11


0  

Dmitry is correct, you should use -lstdc++ if you use gcc, but even better is to use g++ instead. (Same syntax).
Also, you would note (I guess if you add -Wall) that you get a warning that your class with virtual functions is without a destructor, so a good idea is to add a (virtual) destructor to A as well.

Dmitry是正确的,如果您使用gcc,您应该使用-lstdc++,但是最好是使用g++。(语法)。同样,您会注意到(我猜如果您添加了-Wall),您会得到一个警告,您的类具有虚拟函数没有析构函数,所以一个好主意是向a添加一个(虚拟)析构函数。

#1


27  

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 setInstance will 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

还要注意,您必须使用g++编译c++程序,因为它还将c++标准库链接到您的代码中。

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

#2


5  

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"

#3


3  

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

你现在的问题是联系。对于c++程序,必须添加标准c++库:

gcc -o test -lstdc++ test.cpp

测试-lstdc++ test.cpp。

#4


3  

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++测试。cpp - o测试

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

#5


1  

You should store A as a pointer.

您应该将A存储为指针。

A* instance;

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

编辑:我以前写过“参考”。在c++中有一个区别。

#6


1  

You don't have to use pointers if 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);

#7


1  

I had this problem by including parent.h before iostream:

我有个问题,包括父母。h iostream之前:

wrong:

错误的:

include "parent.h"
include <iostream>

right:

正确的:

include <iostream>
include "parent.h"

#8


1  

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++中,抽象类不能用作函数的param或返回类型。我们不能实例化一个抽象对象。

So need to use & or *.

所以需要使用&或*。

#9


0  

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

您必须使用一个指针作为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是抽象的。

#10


0  

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类型的新对象,但是您已经说过,isa是一个抽象类,所以您不能这样做。您需要使用一个指针,就像其他几个人指出的那样,或者做一个非抽象的。

#11


0  

Dmitry is correct, you should use -lstdc++ if you use gcc, but even better is to use g++ instead. (Same syntax).
Also, you would note (I guess if you add -Wall) that you get a warning that your class with virtual functions is without a destructor, so a good idea is to add a (virtual) destructor to A as well.

Dmitry是正确的,如果您使用gcc,您应该使用-lstdc++,但是最好是使用g++。(语法)。同样,您会注意到(我猜如果您添加了-Wall),您会得到一个警告,您的类具有虚拟函数没有析构函数,所以一个好主意是向a添加一个(虚拟)析构函数。