c++继承.更改对象数据类型

C++ Inheritance. Changing Object data Types

本文关键字:对象 数据类型 继承 c++      更新时间:2023-10-16

我在强迫自己的对象更改数据类型时遇到了麻烦。我有一个基类,叫做A,还有两个从A衍生出来的类,叫做BC。我将对象BC传递给一个函数,该函数检查对象的类型(BC)。下面是一些示例代码和我的问题的问题:

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)

当我在函数WhatType中填充了新的vector b_candidate时。我是否仍然可以访问B对象中的成员函数,还是只能访问基类A中的成员函数?

我很困惑,当我改变对象的类型时,对象会发生什么。

这里

WhatType((vector<A*>*) b_exmaple)

B* b = (B*) candidates->at(i);

当你收到一个指向多态对象的指针时,你有两种类型:对象的"静态"类型,在你的情况下,将是A *,以及它的"动态"或"真实"类型,这取决于实际分配给它的内容。

A *转换为B *强制编译器将该指针视为指向B的指针;这是安全的,只要你知道指针实际上是指向B 的指针,否则编译器将开始编写无意义的代码(在其他类型的数据上调用B方法)。

您正在尝试实现的检查是RTTI的一个本地版本,这是一种机制,允许您知道哪个是指针的"真实类型"或对多态类的引用,并安全地执行这种类型的强制转换。查看c++手册中的typeiddynamic_cast以获得更多信息。(顺便说一句,IIRC dynamic_cast不仅是为了在动态类型错误的情况下的安全,而且如果你在复杂的类层次结构中使用指针,它可能还会对指针执行一些额外的魔法;因此,避免多态类的c风格强制转换)

顺便说一下,通常认为必须手动检查指针的"真实类型"才能强制转换它并使用它的方法是"代码气味":OOP理想情况下只能通过基类中可用的virtual方法来完成工作。


重大警告: RTTI只在多态类上工作,即至少有一个虚方法的类。另一方面,如果您正在构建一个类层次结构,其中对象作为指向基类的指针被传递,那么您几乎肯定希望有一个virtual析构函数,所以这没什么大不了的。

由于您强制转换为B*,您将可以访问B的成员

对象的实际的类型当然不会改变,但是如果你只有一个指向基类的指针(或引用),你就不能访问特定于子类的字段。

要访问子类字段,可以使用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

如果在堆上实例化了一个类型为B的对象并由类型为A的指针持有。你只能看到A类型的成员函数,要访问B类型的成员函数,你必须访问static_cast<B*>,也就是…"( B*)"……在干什么。

dynamic cast更好,因为如果转换不可能,它将返回null。当然,这是在运行时发生的,所以有惩罚

由于BCÀ的派生,因此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') {}
         ....
};

使用这个,您将检查您的BC对象没有问题。之后,当您将基对象转换为派生对象时,您将可以完全访问它们的公共方法和属性。