C++ 如何在C+;中将对象的类更改为其当前类的子类+;?

C++ 如何在C+;中将对象的类更改为其当前类的子类+;?,c++,class,type-conversion,subclassing,C++,Class,Type Conversion,Subclassing,我有一个指向基类的指针数组,因此我可以使这些指针指向基类的(不同)子类,但仍然与它们交互。(实际上只有几个方法是虚拟的和重载的)我想知道我是否可以避免使用指针,而只是创建一个基类数组,但是有一些方法可以将类设置为我选择的子类。我知道那里一定有指定类的东西,因为它需要使用它来查找虚方法的函数指针。顺便说一下,这些子类都有相同的IVAR和布局 注意:由于性能的提高,设计实际上是基于使用模板参数而不是变量,因此抽象基类实际上只是子类的接口,这些子类除了编译代码外都是相同的 谢谢 编辑:基类的所有子类(

我有一个指向基类的指针数组,因此我可以使这些指针指向基类的(不同)子类,但仍然与它们交互。(实际上只有几个方法是虚拟的和重载的)我想知道我是否可以避免使用指针,而只是创建一个基类数组,但是有一些方法可以将类设置为我选择的子类。我知道那里一定有指定类的东西,因为它需要使用它来查找虚方法的函数指针。顺便说一下,这些子类都有相同的IVAR和布局

注意:由于性能的提高,设计实际上是基于使用模板参数而不是变量,因此抽象基类实际上只是子类的接口,这些子类除了编译代码外都是相同的

谢谢

编辑:基类的所有子类(如果需要)都具有相同的布局/大小

除此之外,策略模式是好的,但它添加了一个指向类的指针,而我试图避免的恰恰是一种尊重

简单地说,我想做的是

class base {
int ivars[100];
public:
virtual char method() = 0;
}

template <char c>
class subclass : base {
public:
  char method() {
    return c;
  }
}

base things[10];
some_special_cast_thingy(things[2], subclass);
printf("%c", things[2].method());
类基{
int ivars[100];
公众:
虚拟字符方法()=0;
}
模板
类子类:base{
公众:
char方法(){
返回c;
}
}
卑鄙的东西[10];
一些特殊的东西(东西[2],子类);
printf(“%c”,things[2].method());

很明显,它要复杂得多,但就类/任何东西而言,这几乎就是我要寻找的全部。顺便说一句,这可能是一种语言特性。

使用指针和多态性,这就是它们的用途。有一些开销,但它是微乎其微的,除非你在一个非常苛刻的环境。这为以后添加新的子类提供了很大的灵活性。

您可以使用指针数组。如果希望访问派生类接口的某些部分,可以使用dynamic_cast

数组必须是精确类型,因为编译器必须能够计算每个元素的精确位置。因此,您不能混合使用子类,甚至不能将子类数组视为基类数组。

这听起来像是状态模式或策略模式

将数据从类中分离出来,让数组包含数据和指向基类的指针。设置指针,使其根据需要指向不同的子类,但基类方法使用指向数组元素的指针或引用来访问数据。子类实现基类方法,但除传递给方法的数据外,没有其他数据

class Base;

class Data{
  string name;
  int age;
  Base* base;
};

class Base{
  virtual void method1(Data&)=0;
  // other methods
};

class Subclass1: public Base{
  void method1(Data& data){ data.age=0; }
};

vector<Data> dataVector;
Subclass1 subclass1;
Data* someData = ...
someData->base=&subclass1;

someData->base->method1(*someData);
类基;
类数据{
字符串名;
智力年龄;
基地*基地;
};
阶级基础{
虚空方法1(数据&)=0;
//其他方法
};
类子类1:公共基{
void method1(数据和数据){Data.age=0;}
};
向量数据向量;
第1款第1款;
数据*someData=。。。
someData->base=&子类1;
someData->base->method1(*someData);

您遇到的问题与存储分配有关。分配阵列时,阵列需要包含其所有元素的存储。让我举一个(高度简化的)例子。假设您的课程设置如下:

class Base
{
public:
  int A;
  int B;
}

class ChildOne : Base
{
public:
  int C;
}

class ChildTwo : Base
{
public:
  double C;
}
class Data
{
public:
  int A;
  int B;

  Data(HandlerBase* myHandler);
  int DoSomething() { return myHandler->DoSomething(this) }
protected:
  HandlerBase* myHandler;
}

class HandlerBase
{
public:
  virtual int DoSomething(Data* obj) = 0;
}

class ChildHandler : HandlerBase
{
public:
  virtual int DoSomething(Data* obj) { return obj->A; }
}
当您分配一个
基[10]
时,数组中的每个元素将需要(在典型的32位系统上*)8字节的存储空间:足以容纳两个4字节的整数。但是,一个
ChildOne
类需要其父类的8字节存储空间,再加上其成员
C
的4字节存储空间。一个
ChildTwo
类需要其父类的8个字节,再加上其
双C
的8个字节。如果您试图将这两个子类中的任何一个推送到分配给8字节
基的数组中,您的存储将溢出

指针数组工作的原因是它们的大小是恒定的(32位系统中每个都有4个字节),而不管它们指向什么。指向
Base
的指针与指向
ChildTwo
的指针相同,尽管后者的大小是后者的两倍

dynamic_cast
操作符允许您执行类型安全向下转换,将
Base*
更改为
ChildTwo*
,因此它将解决您在这种特殊情况下的问题

或者,您可以通过创建类似以下内容的类布局,将处理逻辑与数据存储(的)解耦:

class Base
{
public:
  int A;
  int B;
}

class ChildOne : Base
{
public:
  int C;
}

class ChildTwo : Base
{
public:
  double C;
}
class Data
{
public:
  int A;
  int B;

  Data(HandlerBase* myHandler);
  int DoSomething() { return myHandler->DoSomething(this) }
protected:
  HandlerBase* myHandler;
}

class HandlerBase
{
public:
  virtual int DoSomething(Data* obj) = 0;
}

class ChildHandler : HandlerBase
{
public:
  virtual int DoSomething(Data* obj) { return obj->A; }
}
如果
DoSomething
的算法逻辑可能需要大量对象共有的重要设置或初始化(并且可以在
ChildHandler
构造中处理),但不通用(因此不适用于静态成员),则此模式适用。然后,数据对象维护一致的存储,并指向将用于执行其操作的处理程序进程,在需要调用某个对象时将其自身作为参数传递<代码>数据
这类对象具有一致的、可预测的大小,可以分组到数组中以保留引用位置,但仍然具有通常继承机制的所有灵活性

请注意,您仍然在构建一个指针数组,但它们只是嵌套在实际数组结构下面的另一层

*对于挑剔者:是的,我意识到我为存储分配给出的数字忽略了类头、vtable信息、填充和大量其他潜在的编译器注意事项。这并不意味着详尽无遗

编辑第二部分:以下所有材料均不正确。我在没有测试的情况下就把它贴在了我的头顶上,把重新解释两个无关指针的能力和转换两个无关类的能力搞混了。我是罪过,多亏了查尔斯·贝利