具体类具体方法

时间:2009-02-13 21:50:38

标签: c++ design-patterns architecture

我有一个有趣的问题。考虑这个课程层次结构:

class Base
{
public:
   virtual float GetMember( void ) const =0;
   virtual void SetMember( float p ) =0;
};

class ConcreteFoo : public Base
{
public:
   ConcreteFoo( "foo specific stuff here" );

   virtual float GetMember( void ) const;
   virtual void SetMember( float p );

   // the problem
   void foo_specific_method( "arbitrary parameters" );
};

Base* DynamicFactory::NewBase( std::string drawable_name );

// it would be used like this
Base* foo = dynamic_factory.NewBase("foo");

我遗漏了DynamicFactory定义以及Builders的定义 在它注册。 Builder对象与名称相关联 并将分配Base的具体实现。实际上 使用shared_ptr处理内存时,实现有点复杂 回收,但它们对我的问题并不重要。

ConcreteFoo具有特定于类的方法。但自具体实例以来 在动态工厂中创建具体类是未知的或 可访问的,它们只能在源文件中声明。我怎么能够 向foo_specific_method的用户公开Base*

我正在添加我提出的解决方案作为答案。我已经命名了 它们可以让你轻松地在答案中引用它们。

我不只是在寻找对我的原始解决方案,新的解决方案的意见 将不胜感激。

10 个答案:

答案 0 :(得分:2)

然而,演员阵容会比大多数其他解决方案更快:

基类中的

添加:

void passthru( const string &concreteClassName, const string &functionname, vector<string*> args )
{
    if( concreteClassName == className )
         runPassThru( functionname, args );
}

private:
    string className;
    map<string, int> funcmap;
    virtual void runPassThru( const string &functionname, vector<string*> args ) {}

在每个派生类中:

void runPassThru( const string &functionname, vector<string*> args )
{
   switch( funcmap.get( functionname ))
   {
      case 1:
          //verify args
          // call function
        break;
      // etc..
   }
}

// call in constructor
void registerFunctions()
{
      funcmap.put( "functionName", id );
      //etc.
}

答案 1 :(得分:1)

CrazyMetaType解决方案。

这个解决方案没有经过深思熟虑。我希望有人可能 有过类似的经历。我看到这适用于 未知数量的已知类型的问题。它很漂亮。一世 正在考虑将它应用于未知类型的未知类型*** S ***

基本思路是CrazyMetaType收集参数类型 安全的方式,然后执行具体的具体方法。

class Base
{
   ...
   virtual CrazyMetaType concrete_specific( int kind ) =0;
};

// used like this
foo->concrete_specific(foo_method_id) << "foo specific" << foo_specific;

我对这个解决方案的担心是CrazyMetaType将是 让这个变得复杂起来非常复杂。我能胜任这项任务,但我 不能指望未来的用户只需要添加c ++专家 一个具体的具体方法。

答案 2 :(得分:0)

Base添加特殊功能。

最简单,最不可接受的解决方案是添加 foo_specific_method到Base。然后那些没有的课程 使用它可以将它定义为空。这不起作用,因为 允许用户注册自己的Builders dynamic_factory。新课程也可能有具体的课程 具体方法。

在这个解决方案的精神,是一个稍微好一点。添加通用 函数Base

class Base
{
   ...
   /// \return true if 'kind' supported
   virtual bool concrete_specific( int kind, "foo specific parameters" );
};

这里的问题是可能存在相当多的重载 具体针对不同的参数集。

答案 3 :(得分:0)

投下它。

当需要特定于foo的方法时,通常你就知道了 Base*实际上是ConcreteFoo。所以只需确保类的定义 ConcreteFoo可以访问,并且:

ConcreteFoo* foo2 = dynamic_cast<ConcreteFoo*>(foo);

我不喜欢这个解决方案的原因之一是dynamic_casts很慢而且 需要RTTI。

下一步是避免使用dynamic_cast。

ConcreteFoo* foo_cast( Base* d )
{
   if( d->id() == the_foo_id )
   {
      return static_cast<ConcreteFoo*>(d);
   }

   throw std::runtime_error("you're screwed");
}

这需要Base类中的另一个方法完全 可以接受,但它需要管理id。这很难 当用户可以在动态工厂注册他们自己的Builders时。

我不太喜欢任何铸造解决方案,因为它需要 要在使用专用方法的位置定义的用户类。 但也许我只是一个范围纳粹。

答案 4 :(得分:0)

cstdarg解决方案。

Bjarn Stroustrup说:

  

一个定义良好的程序最多需要几个函数   参数类型未完全指定。重载函数和   使用默认参数的函数可用于处理类型   在大多数情况下检查否则会考虑离开   参数类型未指定。只有当参数的数量和   参数的类型变化是必要的省略号

class Base
{
   ...
   /// \return true if 'kind' supported
   virtual bool concrete_specific( int kind, ... ) =0;
};

这里的缺点是:

  • 几乎没有人知道如何正确使用cstdarg
  • 感觉不太好c ++ - y
  • 这不是类型安全的。

答案 5 :(得分:0)

你能创建Base的其他非具体子类,然后在DynamicFactory中使用多个工厂方法吗?

你的目标似乎是颠覆子类的重点。我真的很想知道你在做什么需要这种方法。

答案 6 :(得分:0)

如果具体对象具有特定于类的方法,那么它意味着您只是在处理该类的实例时才专门调用该方法,而不是在处理泛型基类时。这是关于b / c你正在运行一个检查对象类型的switch语句吗?

我将从不同的角度处理这个问题,使用“不可接受的”第一个解决方案,但没有参数,具体对象具有可存储其状态的成员变量。虽然我猜这会强制你有一个成员关联数组作为基类的一部分,以避免强制转换为首先设置状态。

您可能还想尝试装饰器模式。

答案 7 :(得分:0)

你可以做类似于CrazyMetaType或cstdarg参数的事情,但是简单和C ++ - ish。 (也许这可能是SaneMetaType。)只需为concrete_specific的参数定义一个基类,并让人们从中派生出特定的参数类型。像

这样的东西
class ConcreteSpecificArgumentBase;

class Base
{
   ...  
   virtual void concrete_specific( ConcreteSpecificArgumentBase &argument ) =0;
};

当然,您需要RTTI在每个版本的concrete_specific内对事物进行排序。但如果ConcreteSpecificArgumentBase设计得很好,至少它会使调用concrete_specific相当简单。

答案 8 :(得分:0)

奇怪的是,DynamicFactory的用户会收到Base类型,但是当它是ConcreteFoo时需要做特定的事情。

也许不应该使用工厂。

尝试查看其他依赖注入机制,例如自己创建ConcreteFoo,将ConcreteFoo类型指针传递给需要它的人,以及指向其他人的Base类型指针。

答案 9 :(得分:0)

上下文似乎假设用户将使用您的ConcreteType并知道它正在这样做。

在这种情况下,如果客户知道他们正在处理具体类型并且需要在该抽象级别工作,那么您的工厂中可能会有另一个返回ConcreteType *的方法。