检查基础 class 对象的子 class - 继承
Checking subclass of base class object - inheritance
我需要在执行时知道我正在使用的 base-class 对象的子类型。
首先,我有一个名为 Element
的基 class。然后,我有几个名为 Car
、Adult
... 的子 classes 都派生自 Element
。在我的代码的某些部分,我创建了一些我存储在 Element
数组中的类型的对象。
当我遍历数组并尝试恢复对象的主要类型时,问题就来了。
我一直在尝试使用 dynamic_cast
这样做,但是每个 Element
都可以成功地转换为 Car
、Adult
或任何...
这是代码:
Element elements[3];
Car c;
Adult a1;
Adult a2;
elements[0] = c;
elements[1] = a1;
elements[2] = a2;
int numElements = 3;
for(int i = 0; i< numElements; i++){
if(dynamic_cast<Adult*>(&elements[i]) == nullptr){
cout << "Its an adult" << endl;
}else{
cout << "Sth else" << endl;
}
}
这就是结果:
Its an adult
Its an adult
Its an adult
这是子classes代码:
class Car : public Element{
...
};
class Adult : public Element{
...
};
您的代码有两个问题。
一个,Element elements[3];
创建一个Element
对象数组。不属于 "objects of classes derived from Element
"。您不能在这样的数组中存储 Element
以外的任何内容,任何这样做的尝试都会导致 object slicing:源对象的非 Element
部分被切掉(丢弃)并且只有 Element
部分出现了。
如果要动态多态,就得用指针或者引用,通常还要动态分配。在您的情况下,这可能看起来像这样:
std::unique_ptr<Element> elements[3];
Car c;
Adult a1;
Adult a2;
elements[0] = std::make_unique<Car>(c);
elements[1] = std::make_unique<Adult>(a1);
elements[2] = std::make_uniuqe<Adult>(a2);
或者,如果您想避免复制对象:
std::unique_ptr<Element> elements[3];
auto c = std::make_unique<Car>();
auto a1 = std::make_unique<Adult>();
auto a2 = std::make_unique<Adult>();
elements[0] = std::move(c);
elements[1] = std::move(a1);
elements[2] = std::move(a2);
或者直接在数组中创建它们:
std::unique_ptr<Element> elements[3];
elements[0] = std::make_unique<Car>();
elements[1] = std::make_unique<Adult>();
elements[2] = std::make_unique<Adult>();
Two,您误解了 dynamic_cast
的结果。如果 dynamic_cast
成功,它将 returns 指针转换为适当的类型。如果失败,它 returns 一个空指针。您的情况相反,因为您将 == nullptr
解释为成功。循环实际上应该是这样的(从第 1 点开始的 unique_ptr
s 到位):
for(int i = 0; i< numElements; i++){
if(dynamic_cast<Adult*>(elements[i].get())){
cout << "Its an adult" << endl;
}else{
cout << "Sth else" << endl;
}
}
一些旁注:
既然你的Element
被用作多态基础class,它应该有一个虚拟析构函数。否则,使用 Element
类型的指针删除从 Element
派生的类型的动态分配对象将导致未定义的行为(很可能是内存损坏)。
如果您的 Element
仅用作抽象基础,并且您从不期望类型完全 Element
的对象(不是从它派生的)存在,您应该 Element
通过给它至少一个纯虚函数(virtual void foo() = 0;
)来抽象。如果它是一个真正的基地 class,它可能自然会包含一些候选者。
在使用基 class 时需要知道确切的派生类型通常是糟糕设计的标志。理想情况下,Element
应该包含虚函数,涵盖您可能需要以类型抽象的方式对对象执行的所有功能。当然也有例外,但您可能应该重新评估您的设计以确保这些 dynamic_casts
确实是必要的。
我需要在执行时知道我正在使用的 base-class 对象的子类型。
首先,我有一个名为 Element
的基 class。然后,我有几个名为 Car
、Adult
... 的子 classes 都派生自 Element
。在我的代码的某些部分,我创建了一些我存储在 Element
数组中的类型的对象。
当我遍历数组并尝试恢复对象的主要类型时,问题就来了。
我一直在尝试使用 dynamic_cast
这样做,但是每个 Element
都可以成功地转换为 Car
、Adult
或任何...
这是代码:
Element elements[3];
Car c;
Adult a1;
Adult a2;
elements[0] = c;
elements[1] = a1;
elements[2] = a2;
int numElements = 3;
for(int i = 0; i< numElements; i++){
if(dynamic_cast<Adult*>(&elements[i]) == nullptr){
cout << "Its an adult" << endl;
}else{
cout << "Sth else" << endl;
}
}
这就是结果:
Its an adult
Its an adult
Its an adult
这是子classes代码:
class Car : public Element{
...
};
class Adult : public Element{
...
};
您的代码有两个问题。
一个,Element elements[3];
创建一个Element
对象数组。不属于 "objects of classes derived from Element
"。您不能在这样的数组中存储 Element
以外的任何内容,任何这样做的尝试都会导致 object slicing:源对象的非 Element
部分被切掉(丢弃)并且只有 Element
部分出现了。
如果要动态多态,就得用指针或者引用,通常还要动态分配。在您的情况下,这可能看起来像这样:
std::unique_ptr<Element> elements[3];
Car c;
Adult a1;
Adult a2;
elements[0] = std::make_unique<Car>(c);
elements[1] = std::make_unique<Adult>(a1);
elements[2] = std::make_uniuqe<Adult>(a2);
或者,如果您想避免复制对象:
std::unique_ptr<Element> elements[3];
auto c = std::make_unique<Car>();
auto a1 = std::make_unique<Adult>();
auto a2 = std::make_unique<Adult>();
elements[0] = std::move(c);
elements[1] = std::move(a1);
elements[2] = std::move(a2);
或者直接在数组中创建它们:
std::unique_ptr<Element> elements[3];
elements[0] = std::make_unique<Car>();
elements[1] = std::make_unique<Adult>();
elements[2] = std::make_unique<Adult>();
Two,您误解了 dynamic_cast
的结果。如果 dynamic_cast
成功,它将 returns 指针转换为适当的类型。如果失败,它 returns 一个空指针。您的情况相反,因为您将 == nullptr
解释为成功。循环实际上应该是这样的(从第 1 点开始的 unique_ptr
s 到位):
for(int i = 0; i< numElements; i++){
if(dynamic_cast<Adult*>(elements[i].get())){
cout << "Its an adult" << endl;
}else{
cout << "Sth else" << endl;
}
}
一些旁注:
既然你的
Element
被用作多态基础class,它应该有一个虚拟析构函数。否则,使用Element
类型的指针删除从Element
派生的类型的动态分配对象将导致未定义的行为(很可能是内存损坏)。如果您的
Element
仅用作抽象基础,并且您从不期望类型完全Element
的对象(不是从它派生的)存在,您应该Element
通过给它至少一个纯虚函数(virtual void foo() = 0;
)来抽象。如果它是一个真正的基地 class,它可能自然会包含一些候选者。在使用基 class 时需要知道确切的派生类型通常是糟糕设计的标志。理想情况下,
Element
应该包含虚函数,涵盖您可能需要以类型抽象的方式对对象执行的所有功能。当然也有例外,但您可能应该重新评估您的设计以确保这些dynamic_casts
确实是必要的。