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

Rhe*_*eel 2 c++ vector object-slicing

我想在a中存储具有相同基类的多个类std::vector.经过一些研究,我很明显我必须使用指针来防止对象切片.但是,当我创建向量时,向其添加元素并返回它,结果向量没有正确的值.

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

class Base {
    public:
        int var0;
}

class Derived : public Base {
    public:
        int var1;
}
Run Code Online (Sandbox Code Playgroud)

这是一个简单的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

首先,这确实像我想要的那样:

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

这打印:

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

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

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

这打印:

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

不是我想要的.我希望它像其他功能一样打印.

有什么方法可以解决这个问题吗?也许任何方式可能做整个派生类的事情好一点?

Bat*_*eba 7

您的程序行为未定义:

Base b;
b.var0 = 23;
vec.push_back(&b);
Run Code Online (Sandbox Code Playgroud)

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

为什么不用一个std::vector<std::unique_ptr<Base>>呢?对象切片不会成为问题,向量将为您管理内存.