我在强制数据类型更改时遇到了问题。我有一个基类说A
和两个派生自A
的类B
和C
。我将对象B
和C
传递给一个函数,该函数检查它是哪种类型的对象(B
或C
)。下面是一些示例代码以及我的问题:
enum ClassType {"B", "C"};
class A {
protected:
m_Type;
public:
ClassType Type() { return m_Type}
...
...
};
class B : public A {
otherMemberFunctions();
}
class C : public A {
otherMemberFunctions();
}
void WhatType(vector<A*>* candidates){
vector<B*> b_candidates(0);
vector<C*> c_candidates(0);
for(int i = 0; i < candidates->size(); i++){
if(candidates->at(i)->Type() == B ){
B* b = (B*) candidates->at(i);
b_candidates(b);
}
//Same idea for Object C
}
}
然后我会使用WhatType(vector<A*>* candidates)
,如下所示
vector<B*>* b_example
WhatType((vector<A*>*) b_exmaple)
当我在函数vector
中填写新的WhatType
b_candidates时。我仍然可以访问B
对象中的成员函数,还是只能访问基类A
中的成员函数?
当我改变对象的类型时,我对该对象会发生什么感到困惑。
下面
WhatType((vector<A*>*) b_exmaple)
在这里
B* b = (B*) candidates->at(i);
答案 0 :(得分:1)
由于您转为B*
,您可以访问B
个成员。
答案 1 :(得分:1)
当然,对象的实际类型不会改变,但如果您只有基类的指针(或引用),则无法访问特定于子类的字段。
访问子类字段的方法是使用dynamic_cast
将其强制转换为子类:
A *a = new B; // We cant reach the members of class B in a
B *b = dynamic_cast<B *>(a); // But now we have a proper pointer to B
答案 2 :(得分:1)
好的,所以如果你有一个类型为B
的对象在堆上实例化并由类型为A
的指针持有。您只能看到类型A
的成员函数,才能访问B
所需的static_cast<B*>
类成员函数,这就是......“(B*
) “ ... 是在做。
dynamic cast
更好,因为如果无法进行转换,它将返回null
。但当然它发生在运行时间,所以有一个惩罚。
答案 3 :(得分:1)
当你收到一个指向多态对象的指针时,你有两种类型:对象的“静态”类型,在你的情况下,它将是A *
,它的“动态”或“真实”类型,这取决于实际分配给它的内容。
将A *
强制转换为B *
会强制编译器将该指针视为指向B
的指针;只要您确实知道指针实际上是指向B
的指针,这是安全的,否则编译器将开始编写无意义的代码(在另一个数据上调用B
方法类型)。
您尝试实现的检查是RTTI的本地版本,这是一种机制,可以让您知道哪个是指针的“实际类型”或对多态类的引用,并执行这种类型的安全地施放。有关它的更多信息,请查看C ++手册中的typeid
和dynamic_cast
。 (顺便提一下,IIRC dynamic_cast
不仅仅是为了安全,以防动态类型错误,但如果你在复杂的类层次结构中使用它,它也可能会对你的指针执行一些额外的魔法;所以,避免使用C风格的转换多态类)
顺便说一下,通常认为“代码气味”必须手动检查指针的“真实类型”才能投射它并使用它的方法:OOP理想只能完成工作虽然基类中有virtual
个方法。
大警告: RTTI仅对多态类工作,即至少有一个虚拟方法的类。另一方面,如果你正在构建一个类层次结构,其中对象作为指向基类的指针传递,你几乎肯定希望有一个virtual
析构函数,所以这没什么大不了的。
答案 4 :(得分:-1)
由于B
和C
是À
派生的,vector<B *>
和vector<C *>
包含A
基类对象。如果您确保在构造函数中设置A::m_Type
属性,则不会出现问题:
enum ClassType {'B', 'C'}; // see I modified your definition
class A {
protected:
ClassType m_Type;
public:
ClassType Type() { return m_Type};
...
...
};
class B : public A {
public:
B() : m_Type('B') {}
....
};
使用此功能,您可以毫无问题地检查B
和C
个对象。之后,当您将基础对象转换为派生对象时,您将完全访问其公共方法和属性。