当子类位于parent类型的向量内时,访问父类中的子成员



在父类向量中有多个子类,每个子类都有自己的类型。父级有一个虚拟getType函数,每个子级都用自己的函数覆盖它;甚至不确定我是否需要这个TBH,但我从这个Access中得到了父类中的子成员,C++

当我在向量上循环时(这里没有显示循环),类型只是父对象的类型,因为它是Parents的向量,但我需要用它自己的构造函数生成每个单独子对象的类型。

#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
}

我该怎么做?我不知道每个人都是什么类型的孩子,或者有其他方法可以做到这一点吗?

您刚刚尝试了切片

Child就是Parent加上更多的东西。

当您尝试将Child放在Parent的向量中时,只有这些Children中的每一个的Parent部分放在向量中(因为向量不包含Children,而是包含Parents);因此命名为切片

为了获得您正在寻找的动态多态性,您需要一个指向Parent指针的向量;这样,每个指向的元素可以是Parent还是Child,并相应地表现。

这通常是通过对向量中的每个元素进行动态分配来完成的,但这不是强制性的。例如,您可以将所有的Parent存储在一个向量中,将所有Child存储在另一个向量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;
}

最新更新