如何避免特定类方法的 C++ 强制转换?设计模式?

Posted

技术标签:

【中文标题】如何避免特定类方法的 C++ 强制转换?设计模式?【英文标题】:How to avoid C++ cast for specific class methods? Design Pattern? 【发布时间】:2011-03-25 12:15:04 【问题描述】:

假设我有这样的事情:

class Father 
    public:
      virtual int genericMethod (void) =0;
  ;

class Son1: public Father 
  public:
    int genericMethod ()
       
  ;

class Son2: public Father 
  public:
    int genericMethod ()
       
    int specifClassMethod()
       
  ;

我主要做以下事情:

Father * test = new Son2();

test->specifClassMethod(); //Can't do this! It is specific of Class Son2 and is not a virtual method in class Father!

这里的主要问题是知道通过Father接口访问Son2特定方法的更好方法。我想知道是否有设计模式可以解决这个问题或其他方式。我不想做演员表,也不想在我的代码中放很多“如果”。

问候,

爱德华多

【问题讨论】:

你的例子有点做作,能不能说的更具体一点? 为了比@Coda 更明确,您使用的实际设计是什么,以便我们指出其中的缺陷?如果你的设计没问题,那么dynamic_cast 就是你的朋友。通常,使用dynamic_cast 是嗅到代码的标志。 不要忘记在基类中添加虚拟析构函数。否则删除“Father* test = ...; delete test;”不会调用正确的析构函数。 【参考方案1】:

也许访客模式就是您正在寻找的模式。

How Visitor Pattern avoid downcasting

【讨论】:

【参考方案2】:

可能的方法是有特定的接口和可选方法,以及在基类中获取这个接口的虚拟方法(可能返回零):

class SpecificInterface 
public:
  virtual ~SpecificInterface()
   
  virtual int specifClassCmethod() = 0;
   
;

class Father 
  public:
    virtual int genericMethod (void) = 0;
    virtual SpecificInterface* getSpecificInterface (void) =0;
;

class Son1: public Father 
  public:
    int genericMethod ()
       
    SpecificInterface* getSpecificInterface (void)
       return 0; 
  ;

class Son2: public Father, public SpecificInterface 
  public:
    int genericMethod ()
       
    int specifClassCmethod()
       
    SpecificInterface* getSpecificInterface (void)
       return this; 
  ;

用法如下:

Father * test = new Son1();
SpecificInterface * specificAPI = test->getSpecificInterface();
if( specificAPI )
  specificAPI->specifClassCmethod();

【讨论】:

【参考方案3】:

你也不能通过强制转换合法地解决这个问题,因为“test”指向的是一个父亲对象,而不是一个 Son2 对象。转换对象类型意味着“相信我,编译器,这个变量实际上包含 X”。它不会以某种方式神奇地将基础对象转换为派生对象。它只会告诉编译器你已经知道它不知道的东西。

如果您想要因派生类而不同的行为,则将行为移至虚拟方法中——即,要调用 specificCLassMethod() 的代码属于父亲的虚拟方法。

【讨论】:

dynamic_cast 用于此目的。 不,这根本不是 dynamic_cast 所做的:它不能在物理上将一种类型转换为另一种类型。如果我有一个指向基址的指针,它实际上指向派生的实例,反之亦然,dynamic_cast 可以偏移指针以解决 vtbls 或其他隐藏的对象模型问题。这仅在对象的真实运行时类型如我所说的那样有效。 dynamic_cast 不能神奇地将 Son2 的成员变量添加到父亲实例中。【参考方案4】:

没有。要调用仅存在于子类中的方法,您必须强制转换为子类。

虽然您可以创建将函数名称映射到函数的映射,但从子类的构造函数中将函数添加到其中,然后使用 test->callMethod("name"); 之类的东西,您必须使所有这些方法具有相同的签名或使用可变参数来传递不是很好的参数。

【讨论】:

【参考方案5】:

您可以static_cast<Son2*>(test)->specifClassCmethod();,但只有在Father * test = new Son2(); 时才有效

【讨论】:

【参考方案6】:

如果您确实有特定于 Son2 的内容,那么您应该使用 dynamic_cast<>。如果它可以作为虚函数添加到具有默认空行为的基类中,那么您可以在没有强制转换的情况下解决您的问题(但这不是您在问题中所说的想要做的)

解决您的问题的一种设计模式是使用proxy object。该对象将拥有所有易于调用的方法,并将它们委托给真实对象。

代理模式的优点:

您将区分背后对象所需的逻辑集中到一个地方 您可以轻松添加一些日志记录 客户端代码保持简单,Son 类清除了多余的东西

【讨论】:

【参考方案7】:

首先,你不能为“父亲”类创建一个实例,因为它是一个抽象类(它具有 virtual int genericMethod (void) =0; -pure virtual function)。相反,可以将实例分配给它....

喜欢

Son1* obj_son = new Son1();
Father* obj = obj_son;
//now if you call generic method - son1 method will be called(Father method is over ridden)
obj->genericMethod();
//similarly for son2 class
Son2* obj_son2 = new Son2();
Father* obj2 = obj_son2;
obj2->genericMethod();
obj2->specifClassCmethod();

【讨论】:

以上是关于如何避免特定类方法的 C++ 强制转换?设计模式?的主要内容,如果未能解决你的问题,请参考以下文章

c++有混合类型吗

c++ 多重继承强制转换

如何强制在 Visual C++ 的发布模式下创建函数 [重复]

C++ 之 强制转换

模板类的 C++ 强制转换

ForEach 方法中的类强制转换异常