在C++中使用抽象类

sea*_*ges 16 c++ parameters abstract-class

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

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

我现在提交我比Java更熟悉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;
}
Run Code Online (Sandbox Code Playgroud)

此示例产生与我在程序中获得的相同的编译器错误:

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
Run Code Online (Sandbox Code Playgroud)

更新

感谢大家的反馈.

我已经改变了"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
Run Code Online (Sandbox Code Playgroud)

我的修改后的代码如下(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;
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*itb 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;
    }
Run Code Online (Sandbox Code Playgroud)

然后,您必须将类中的成员更改为指针.它不能作为引用,因为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;
Run Code Online (Sandbox Code Playgroud)

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

g++ -o test test.cpp # instead of gcc!
Run Code Online (Sandbox Code Playgroud)


Eri*_*lje 5

你正在做什么将在Java中工作,因为声明类型为"A"的参数或成员变量实际上意味着"指向A的指针".在C++中,你实际上需要明确这一点,因为它们是两个不同的东西:

void setInstance(A* newInstance) { // pointer to an "A"
                instance = newInstance;
}
Run Code Online (Sandbox Code Playgroud)

并在声明中:

A* instance; // Not an actual "A", but a pointer to an "A"
Run Code Online (Sandbox Code Playgroud)