没有对象切片的多态向量 [C++]
Polymorphic Vectors Without Object Slicing [C++]
我正在尝试在 std::array
(或任何其他容器)中存储一些从基础 class 派生的对象,而不进行对象切片。
下面代码片段的期望输出是:
Hi from child1!
Hi from child2!
代码:
#include <iostream>
#include <array>
#include <memory>
class Base {
public:
void hello() {
std::cout << "This shouldn't print\n";
}
};
class Child1 : public Base {
public:
void hello() {
std::cout << "Hi from child 1!\n";
}
};
class Child2 : public Base {
public:
void hello() {
std::cout << "Hi from child 2!\n";
}
};
std::array<std::unique_ptr<Base>, 2> array = {std::make_unique<Child1>(Child1()), std::make_unique<Child2>(Child2()) };
int main() {
for (auto &i : array) {
i->hello();
}
}
我实际从代码中得到的输出是:
This shouldn't print
This shouldn't print
很明显派生对象已经被切片了。有什么办法可以避免这种情况吗?
提前感谢您提供的任何建议。
Obviously the derived objects have been sliced.
实际上,没有。他们没有被切片。您在将 base-class 指针存储到数组中的 derived-class 对象方面做的是正确的。
不,代码没有按照您想要的方式工作,不是因为对象切片,而是因为您根本没有将 hello()
标记为 virtual
和 Base
override
中派生类。因此,当您在循环内调用 i->hello()
时,不会执行多态分派。
此外,您使用的 std::make_unique()
不正确。 make_unique<T>()
的参数被as-is传递给T
的构造函数。在这种情况下,您是 copy-constructing 您的 Child1
/Child2
类 来自临时 Child1
/Child2
对象,这是没有必要的。你可以摆脱临时工。
您在 Base
中还缺少 virtual
析构函数。当您的数组超出范围并且 unique_ptr
尝试在其 Base*
指针上调用 delete
时,这将导致 未定义的行为 。只会调用 Base
析构函数,不会调用 Child1
/Child2
析构函数。
试试这个:
#include <iostream>
#include <array>
#include <memory>
class Base {
public:
virtual ~Base() = default;
virtual void hello() {
std::cout << "This shouldn't print\n";
}
};
class Child1 : public Base {
public:
void hello() override {
std::cout << "Hi from child 1!\n";
}
};
class Child2 : public Base {
public:
void hello() override {
std::cout << "Hi from child 2!\n";
}
};
int main() {
std::array<std::unique_ptr<Base>, 2> array = {
std::make_unique<Child1>(),
std::make_unique<Child2>()
};
for (auto &i : array) {
i->hello();
}
}
我正在尝试在 std::array
(或任何其他容器)中存储一些从基础 class 派生的对象,而不进行对象切片。
下面代码片段的期望输出是:
Hi from child1!
Hi from child2!
代码:
#include <iostream>
#include <array>
#include <memory>
class Base {
public:
void hello() {
std::cout << "This shouldn't print\n";
}
};
class Child1 : public Base {
public:
void hello() {
std::cout << "Hi from child 1!\n";
}
};
class Child2 : public Base {
public:
void hello() {
std::cout << "Hi from child 2!\n";
}
};
std::array<std::unique_ptr<Base>, 2> array = {std::make_unique<Child1>(Child1()), std::make_unique<Child2>(Child2()) };
int main() {
for (auto &i : array) {
i->hello();
}
}
我实际从代码中得到的输出是:
This shouldn't print
This shouldn't print
很明显派生对象已经被切片了。有什么办法可以避免这种情况吗?
提前感谢您提供的任何建议。
Obviously the derived objects have been sliced.
实际上,没有。他们没有被切片。您在将 base-class 指针存储到数组中的 derived-class 对象方面做的是正确的。
不,代码没有按照您想要的方式工作,不是因为对象切片,而是因为您根本没有将 hello()
标记为 virtual
和 Base
override
中派生类。因此,当您在循环内调用 i->hello()
时,不会执行多态分派。
此外,您使用的 std::make_unique()
不正确。 make_unique<T>()
的参数被as-is传递给T
的构造函数。在这种情况下,您是 copy-constructing 您的 Child1
/Child2
类 来自临时 Child1
/Child2
对象,这是没有必要的。你可以摆脱临时工。
您在 Base
中还缺少 virtual
析构函数。当您的数组超出范围并且 unique_ptr
尝试在其 Base*
指针上调用 delete
时,这将导致 未定义的行为 。只会调用 Base
析构函数,不会调用 Child1
/Child2
析构函数。
试试这个:
#include <iostream>
#include <array>
#include <memory>
class Base {
public:
virtual ~Base() = default;
virtual void hello() {
std::cout << "This shouldn't print\n";
}
};
class Child1 : public Base {
public:
void hello() override {
std::cout << "Hi from child 1!\n";
}
};
class Child2 : public Base {
public:
void hello() override {
std::cout << "Hi from child 2!\n";
}
};
int main() {
std::array<std::unique_ptr<Base>, 2> array = {
std::make_unique<Child1>(),
std::make_unique<Child2>()
};
for (auto &i : array) {
i->hello();
}
}