C ++:从基类型指针确定派生类型

时间:2013-11-05 05:41:44

标签: c++

背景

请参阅this question in the C++ FAQ,了解我需要解决的类似情况,但使用命名构造函数。

我有一个基类class B

我有一个来自B的派生类class D,它通过函数,成员和额外的内存分配添加了额外的功能

class B通过不执行任何操作或从特定于nullptrs的虚拟函数返回默认值和class D来多态支持其他功能。

class B使用public static Factory Methods构建所有protected constructors。 (见:Named Constructor Idiom

class D使用public static Factory Methods构建所有protected constructors,其命名与B类不同,但在B类中不可用。

稍后,会创建一个新的接口类class A。此类具有一个接口,使得class A中的派生类必须具有getter函数和setter函数,这两者都需要pointer to a class B,但动态值可以是class B或{{1 }}

问题:

我想派生class D并为class A创建一个复制构造函数,赋值运算符和/或setter,但因为class B只将其成员公开为一个对象类型class A我无法确定返回的对象是B还是class B

如何仅使用公共接口正确实现上述内容而不会导致切片或内存问题(包括上述设置错误并需要更改)?

可能的解决方案?:

我很想尝试几种选择:

1)在B类中创建一个成员,以及声明对象类型的所有派生类型:

class D

2)动态转换为派生类型并检查失败:

if(getB()->GetType() == "D") {
    //Call D::CreateD(...)
} else if(getB()->GetType() == "B") {
    //Call B::CreateB(...)
}

3)在if(dynamic_cast<D*>(getB()) == nullptr) { //Call B::CreateB(...) } else { //Call D::CreateD(...) } 对象上使用时,使用我知道返回class D的{​​{1}}特定的虚拟方法:

nullptr

所有三个案例都有代码味道:

  1. 导致“else-if-heimers”。
  2. 不太确定这实际上会有效。
  3. 违反“代码到接口而非实现”的良好做法。

1 个答案:

答案 0 :(得分:2)

根据zneak的评论,我认为如果你正在使用工厂方法和私有构造函数,那么就没有什么东西可以用了

 virtual B* copy() const { return new B(*this); /* calls private B::B(const B&) */ }
B中的

方法,在类D中重写(返回一个新的D* - 在C ++中特别允许使用协变返回类型。

然后你的A拷贝构造函数可以执行类似

的操作
A::A(const A& other) : b(other.getB()->copy()) {}

它应该可以正常工作。


另一方面,如果你更愿意使用你建议的解决方案之一,我认为第一个是最不刺激的 - 虽然我会选择枚举而不是字符串,所以你可以使用简单的switch语句而不是字符串比较。我相信LLVM使用类似这样的东西进行“动态转换”,以避免C ++ RTTI开销。