具有自动存储持续时间的虚拟功能似乎不起作用

Virtual functions with automatic storage duration does not seem to work

我在对使用自动存储持续时间声明的对象使用虚函数时遇到问题。这是一个可重现的场景:

#include <iostream>

class A {
    public:
        A() {}
        virtual ~A() {}
        virtual void printClassName() {
            std::cout << "A" << std::endl;
        }
};

class B : public A {
    public:
        B() : A() {}
        ~B() {}
        void printClassName() {
            std::cout << "B" << std::endl;
        }
};

class Test {
    private:
        A item;

    public:
        Test() {}
        ~Test() {}
        void setItem(A item) {
            this->item = item;
        }
        A getItem() {
            return this->item;
        }
};

int main() {
    Test t;
    B item;

    t.setItem(item);
    t.getItem().printClassName();

    return 0;
}

这会打印 "A",而我希望它会打印 B。我很好奇为什么。

提前致谢!

这种现象称为对象切片

基本上,当您将 itemB 类型)传递给 setItem(需要 A)时,您将失去 B的每个条信息,因为B不能存储在A.

所以,当你调用 printClassName 时,它只知道来自 A 的那个函数,所以它从 A.

调用它

一种可能的解决方案是传递指向对象的指针,而不是原始数据。这将在您的示例中调用 BprintClassName,因为没有发生切片。

slicing 在这里:

void setItem(A item) {
    this->item = item;
}

当您将 item 传递给 setItem() 时,B 部分被切掉,因此您将丢失其基础部分。如果 A 是抽象的,这将是一个更明显的错误(因为您不能按值存储抽象 class)。

相反,您需要将项目存储为指针。

为了清楚起见,在这种情况下要避免对象切片,您应该将 void setItem(A item) 更改为 void setItem(A& item) 并将 A getItem() 更改为 A& getItem()

这(passing/returning 通过引用)保留了动态类型并且几乎可以肯定这就是您在这种情况下想要的

编辑: 我忽略了一个事实,即您存储的对象也是 A 类型。这行不通。您需要将它作为指针,以便它能够具有与其静态类型(或引用,但随后必须在构造函数中初始化)不同的动态类型。

所以要更改为使用指针,您可以尝试将 Test 中的 A item 更改为 A* item。然后set/get变成:

    void setItem(A& item) {
        this->item = &item;
    }
    A& getItem() {
        return *(this->item);
    }

这为您提供了所需的输出。如果您只是测试多态行为,这没问题,但在实际设计中需要非常小心(例如,您可能想考虑是否应该使用 std::shared_ptr 共享所有权)。