c++防止std::vector中的对象切片

c++ prevent object slicing in std::vector

本文关键字:对象 切片 vector 防止 std c++      更新时间:2023-10-16

我想在std::vector中存储多个具有相同基类的类。经过一些研究,我发现我必须使用指针来防止对象切片。然而,当我创建向量,向其添加元素并返回时,生成的向量没有正确的值。

举个例子,这里是我的两个类:

class Base {
    public:
        int var0;
}
class Derived : public Base {
    public:
        int var1;
}

这里有一个简单的print函数。通常,Base的所有实例都应该具有var0 == 23,而Derived的所有实例应该具有var0 != 23

void print(Base& value) {
    if (value.var0 == 23) {
        std::cout << "Base: " << value.var0 << std::endl;
    } else {
        Derived d = (Derived&) value;
        std::cout << "Derived: " << d.var0 << ", " d.var1 << std::endl;
    }
}

首先,这个可以像我希望的那样工作:

int main() {
    int num = 10;
    std::vector<Base*> vec;
    for (int i = 0; i < num; i++) {
        if (i % 2 == 0) {
            Base b;
            b.var0 = 23;
            vec.push_back(&b);
        } else {
            Derived d;
            d.var0 = 17;
            d.var1 = 42;
            vec.push_back(&d);
        }
    }
    // ....
    for (int i = 0; i < num; i++) {
        print(*vec.at(i));
    }
}

此打印:

Base: 23
Derived: 17,42
Base: 23
Derived: 17,42
Base: 23
Derived: 17,42
Base: 23
Derived: 17,42
Base: 23
Derived: 17,42

现在,我希望这个向量由一个函数返回,所以我创建了一个函数:

std::vector<Base*> createVector(int num) {
    std::vector<Base*> vec;
    for (int i = 0; i < num; i++) {
        if (i % 2 == 0) {
            Base b;
            b.var0 = 23;
            vec.push_back(&b);
        } else {
            Derived d;
            d.var0 = 17;
            d.var1 = 42;
            vec.push_back(&d);
        }
    }
    return vec;
}
int main() {
    int num = 10;
    std::vector<Base*> vec = createVector(num);
    // ....
    for (int i = 0; i < num; i++) {
        print(*vec.at(i));
    }
}

此打印:

Derived: 2293232,0
Derived: 17,42
Derived: 2293232,0
Derived: 17,42
Derived: 2293232,0
Derived: 17,42
Derived: 2293232,0
Derived: 17,42
Derived: 2293232,0
Derived: 17,42

这不是我想要的。我希望它像其他函数一样打印。

有什么办法解决这个问题吗?有什么方法可以让整个派生类的事情做得更好一点吗?

您的程序行为未定义:

Base b;
b.var0 = 23;
vec.push_back(&b);

正在将指向超出范围的变量(b)的指针推回。

为什么不使用std::vector<std::unique_ptr<Base>>呢?对象切片将不是一个问题,矢量将为您管理内存。

这与对象切片无关,而是与在向量中存储指向局部变量的指针有关。一旦变量在其中声明的作用域结束,变量就会被销毁,留下杂散指针,并且取消引用这些杂散指针会导致未定义的行为

你也有这个问题,你说的程序运行良好。看似工作良好是未定义行为的一种或多种可能性。