在基本赋值中存储派生然后调用基本函数

Store derived in base assignement then call base function

我来自 Java,对 C++ 有点陌生。 在 Java 中,我可以这样做:link to code

我创建了一个抽象基 class Mother,在同一基 class.

的 public 函数中使用了一个纯虚函数

我试过了:

class Mother {
    private:
        virtual void bar() = 0;
    public:
        void foo();
};

void Mother::foo() {
    // ... some code
    bar();
}

class Child0: public Mother {
    private:
        void bar();
};

void Child0::bar() {
    std::cout << "Child0" << std::endl;
}

class Child1: public Mother {
    private:
        void bar();
};

void Child1::bar() {
    std::cout << "Child1" << std::endl;
}

// main code
int main() {
    Mother mother;
    if(condition) {
        Child0 child;
        mother = child;
    } else {
        Child1 child;
        mother = child;
    }
    mother.foo();
}

但是我得到一个编译器错误:

main.cpp:35:12: fatal error: variable type 'Mother' is an abstract class
    Mother mother;
           ^
main.cpp:5:22: note: unimplemented pure virtual method 'bar' in 'Mother'
        virtual void bar() = 0;
                     ^

我错过了什么?

您错过了 object slicing 陷阱,并且还有未定义的行为:当您分配

mother = child;

child 将 "sliced" 降低到 mother,并删除任何多态行为。

如果你想保留多态性,使用指针:

Mother *mother;
if(condition) {
    mother = new Child0;
} else {
    mother = new Child1;
}
mother->foo();
delete mother;

确保 Mother 有一个虚拟析构函数。

请注意,您不能再使用内部作用域中的对象,因为一旦作用域结束,指针就会失效:

// Do not do this!
Mother *mother;
if(condition) {
    Child0 child;
    mother = &child;
}
mother->foo(); // <<<=== This is undefined behavior

C++ 与 Java 不同,它具有值语义并且没有隐式指针:当您声明 Mother mother; 时,您将获得 Mother 的实际实例。不多也不少。除了你的情况,其中 Mother 是抽象的:你 不能 有一个 Mother!
的实例 稍后执行 mother = child; 只是将 child 的 Mother 部分分配给 mother。这称为 "object slicing",因为您希望复制的 child 部分也被切掉了。

要解决此问题,您需要使用指针或引用,它们都可以引用动态类型不同于静态类型的 object(例如,Mother 实际上是Child0)。我将使用最简单的拥有指针,std::unique_ptr:

int main() {
    std::unique_ptr<Mother> mother;

    if(condition) {
        mother = std::make_unique<Child0>();
    } else {
        mother = std::make_unique<Child1>();
    }

    // At this point, *mother is of static type Mother,
    // but of dynamic type Child0 or Child1.

    mother->foo();
}

请注意,我也已切换到动态分配:您的两个 children 实例是自动变量,这意味着它们会在其范围 {} 结束时死亡。 std::make_unique 构造一个具有动态生命周期的 object:它只会在持有它的 unique_ptr 死亡时死亡。

如另一个答案所述,由于您的 child object 将通过 Mother 的类型以多态方式被破坏,Mother 的析构函数应该是 virtual 正确发送。

class Mother {
    // ...
public:
    virtual ~Mother() = default;
};