我在父类向量中有多个子类,其中每个子类都有自己的类型。父级有一个虚getType函数,每个子级都用它自己的覆盖它;甚至不确定我是否需要这个 TBH,但我从父类 C++ 中的这个Access 子成员那里得到了
当我循环遍历向量(此处未显示循环)时,类型只是父对象的类型,因为它是父对象的向量,但我需要使用它自己的构造函数创建的每个子对象的类型。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Parent
{
private:
string type = "parent";
public:
virtual string getType()
{
return type;
}
};
class Child1 : public Parent
{
string type = "type1";
public:
string getType()
{
return type;
}
};
class Child2 : public Parent
{
string type = "type2";
public:
string getType()
{
return type;
}
};
//main.cpp
int main()
{
vector<Parent> children;
Child1 t1;
Child2 t2;
children.push_back(t1);
children.push_back(t2);
//THIS WORKS
cout << t1.getType(); // returns type1
// I NEED THIS TO WORK
cout << children[0].getType(); // returns parent.
cout << children[1].getType(); // I need type1 && type2
}
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?我无法知道每个孩子是什么类型的孩子,或者有其他方法可以做到这一点吗?
您刚刚尝试了切片。
AChild是Parent加了一些东西。
当您尝试将 aChild放入 的向量中时Parent,仅将Parent这些Children 中的每一个的一部分放入向量中(因为向量中不包含Children 而是包含Parents);因此得名切片。
为了获得你正在寻找的动态多态,你需要的向量的指针来Parent; 这样,每个指向的元素都可以是 aParent或 aChild并相应地表现。
这通常通过向量中每个元素的动态分配来完成,但这不是强制性的。例如,您可以将所有Parents存储在一个向量中,所有Children 1 存储在另一个中,依此类推,最后使用指针向量以任意顺序指定其中的一些。
如果您决定单独分配每个Parent/ Child,您应该考虑使用智能指针std::unique_ptr<T>而不是原始指针和new/ delete。
您会在下面的示例中发现稍加修改以获得动态多态性。由于std::unique_ptr<T>/ ,它依赖于每个元素的动态分配std::make_unique()。
请注意,由于动态多态性,您需要一个virtual析构函数(即使它没有什么特别之处)。由于此类型层次结构旨在用于动态多态性,因此鼓励通过禁止使用复制/移动操作来防止切片(您刚刚经历过)。因此,您必须提供一个或多个满足您需求的构造函数(但这很常见)。
我的最后一个建议是“避免动态多态;喜欢template» 但这是另一个话题;^)
/**
g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
-pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#include <iostream>
#include <string>
#include <vector>
#include <memory> // std::unique_ptr<T>, std::make_unique()
class Parent
{
public:
virtual ~Parent() =default; // ensure correct destruction
// forbid copy and move in order to prevent slicing
Parent(const Parent &) =delete;
Parent &operator=(const Parent &) =delete;
Parent(Parent &&) =delete;
Parent &operator=(Parent &&) =delete;
Parent() =default; // provide a suitable constructor
virtual
const std::string &
getType() const
{
return type;
}
private:
// inline static // is probably better
const std::string type{"parent"};
};
class Child1: public Parent
{
public:
const std::string &
getType() const override
{
return type;
}
private:
// inline static // is probably better
const std::string type{"type1"};
};
class Child2 : public Parent
{
public:
const std::string &
getType() const override
{
return type;
}
private:
// inline static // is probably better
const std::string type{"type2"};
};
int
main()
{
const auto p=Parent{};
std::cout << "p: " << p.getType() << '\n';
const auto c1=Child1{};
std::cout << "c1: " << c1.getType() << '\n';
const auto c2=Child2{};
std::cout << "c2: " << c2.getType() << '\n';
auto people=std::vector<std::unique_ptr<Parent>>{};
for(auto i=0; i<2; ++i)
{
people.emplace_back(std::make_unique<Parent>());
people.emplace_back(std::make_unique<Child1>());
people.emplace_back(std::make_unique<Child2>());
}
for(const auto &e: people)
{
std::cout << e->getType() << '\n';
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)