0

这是我能找到的最接近可能重复的东西。然而,答案仍然给我留下了疑问。

这是一个代码示例:

class A {
   A() {}
   virtual void print() = 0;
}

class B : public A {
   B() {}
   void print() { printf("B"); }
}

class C : public A {
   C() {}
   void print() { printf("C"); }
}

int main() {
   A** n;

   n = new A*[4];
   n[0] = new B;
   n[1] = new C;
   n[2] = new B;
   n[3] = new C;

   for(int i = 0; i < 4; i++)
      n[i]->print();
   printf("\n");

   delete n[0];
   delete n[1];
   delete n[2];
   delete n[3];
   delete [] n;
}

使用这段代码,您将获得“BCBC”。有没有办法在不分配新对象的情况下更改派生类类型?就像是:

n[2] = (C*)n[2];

因此,当您打印出数组时,您现在会得到“BCCC”。我在链接的帖子中读到,必须这样做是设计不佳的证据。如果是这样的话,能解释一下吗?对我来说,这似乎是面向对象设计的一个正常且频繁的用例。假设所有属性都在基类中定义。类的唯一区别在于方法的实现。

如果 C++ 不支持在运行时更改这样的对象类型,那么获得类似结果的公认方法是什么?

4

4 回答 4

1

最接近的方法是在 B 和 C 构造函数中实现,它们将接受 A(或 A*)作为输入并将任何需要的数据复制到新对象中。然后你应该得到这样的东西。

A* temp = n[2];  
n[2] = new C(A);  
delete temp;  

但更好的解决方案是创建将保存数据的类,并且 A* 指向实现不同数据操作方式的类。

于 2013-04-10T16:52:50.070 回答
0

我不相信你可以从 B 类转换到 C 类。这两个类也是 A 类,因为 B 是 A,C 是 A,但是 B 不是 C,C 不是 B。要么可以转换为 A 但由于切片问题,这是一种危险的做法。在这种情况下,派生类中的数据不会因强制转换而丢失,因此您不会丢失任何东西。但是,您无需将 B 或 C 转换为 A 即可调用父类方法。

也许可以编写一个将 B 对象作为输入并返回 C 对象的函数和一个将 C 对象作为返回 B 对象的函数,但您必须自己完成所有工作,手动将其转换为其他。

于 2013-04-10T16:46:35.300 回答
0

一旦创建了对象,您就无法真正更改它的类型。但这并不意味着您不能在运行时更改行为。你需要做的是重构你的代码。

class A;

class ImplA
{
public:
  void print (A&) = 0;
};

class A
{
  std::unique_ptr<ImplA> impl;

public:
  A (ImplA* ia) : impl(ia)
  {}

  void print()
  {
    impl->print(*this);
  }

  void changeImpl (ImplA* ia)
  {
    impl.reset(ia);
  }
};

这当然是使用 C++11 的智能指针,但无论如何想法都是一样的。您应用软件工程的基本定理:抽象变化的事物。

我建议您阅读设计模式。它会在不破坏 OOP 工作方式的情况下为您提供做您想做的事情的想法。

于 2013-04-10T17:14:11.257 回答
0

指针指向的对象n[2]B对象。它不能神奇地变成一个C物体。如果你想要一个C对象,你将不得不创建一个。但是,不要忘记delete现有B对象。

delete n[2];
n[2] = new C;
于 2013-04-10T16:42:48.990 回答