从基指针/引用

时间:2016-11-25 10:09:57

标签: c++ design-patterns polymorphism virtual

让一个类层次结构:

class Base { virtual ~Base() throw(); };

class DerivedA : public Base { };

class DerivedB : public Base { };

我希望有一些特定于这些派生类的代码。但是,该代码也特定于使用此类层次结构的应用程序,我不希望将这个派生类特定的代码嵌入到这些派生类中。为避免这样做,我考虑过编写自由函数:

void DerivedASpecificWork( DerivedA da );

void DerivedBSpecificWork( DerivedB db );

但是,当通过引用/指向Base的指定给定派生类的实例时,我无法访问实例的实际类型,因此无法调用正确的Derived * SpecificWork()函数。

我想知道是否有一种设计模式可以让我在不知道实例的实际类型的情况下调用派生类特定的函数,即具有与虚函数相同的机制,但是没有拥有这些虚拟函数需要我将特定于应用程序的代码嵌入到该类层次结构中。

实际上,为什么我要这样做是为了提供有关在由Lua脚本调用的本机实现的函数中发生的异常的信息。每个异常都带有自己的一组信息,我希望在脚本中表示错误的方式取决于异常的类型。我可以在基类中创建一个由派生类实现的纯虚方法,但这需要我将Lua相关的代码嵌入到我的异常层次结构中,我不想这样做,因为Lua特定于其中一个使用该异常层次结构的应用程序。

我也不能使用C ++ 11。

谢谢。

3 个答案:

答案 0 :(得分:2)

可能是Brigde模式可以帮到你。

当您想要避免抽象与其实现之间的永久绑定时,可以使用此模式。

(我没有看到您对使用c ++ 11的限制的评论,但您可以删除std::unique_ptrstd::moveoverride关键字)

class AppSpecificImp
{
public:
   virtual void DoWork() = 0;
};

class Base 
{ 
public:
   virtual ~Base() throw(); 

   virtual DoWork() = 0;
};

class DerivedA : public Base 
{ 
public:
   DerivedA(std::unique_ptr<AppSpecificImp> appImp)
      : imp(std::move(appImp))
   {
   }

   void DoWork() override
   {
       // DerivedA specific code 

       imp->DoWork();
   }

private:
   std::unique_ptr<AppSpecificImp> imp;
};

class DerivedB : public Base 
{ 
public:
   DerivedB(std::unique_ptr<AppSpecificImp> appImp)
      : imp(std::move(appImp))
   {
   }

   void DoWork() override
   {
       // DerivedB specific code 

       imp->DoWork();
   }

private:
   std::unique_ptr<AppSpecificImp> imp;
};

修改以显示访客模式使用情况:

使用访客模式,您可以做您想做的事情,但需要更多的努力。

class Visitor
{
public:
   virtual void VisitDerivedA(DerivedA* object) = 0;

   virtual void VisitDerivedB(DerivedB* object) = 0;
};

class Base
{
public:
   virtual void Visit(Visitor* visitor) = 0;
};

class DerivedA : public Base 
{ 
public:
   virtual void Visit(Visitor* visitor)
   {
       visitor->VisitDerivedA(this);
   }
};

class DerivedB : public Base 
{ 
public:
   virtual void Visit(Visitor* visitor)
   {
       visitor->VisitDerivedB(this);
   }
};

class AppSpecificVisitor : public Visitor
{
public:
   void VisitDerivedA(DerivedA* object)
   {
       // Do any work related to DerivedA class
   }

   void VisitDerivedB(DerivedB* object)
   {
       // Do any work related to DerivedB class
   }
}


int main()
{
    AppSpecificVisitor myVisitor;

    Base* myBase = // any class in your hierarchy

    myBase->Visit(&myVisitor);
}

正如我在访问者模式的评论中所说,您可以在不更改主层次结构的情况下添加新功能(Base-&gt;派生类型)。您只需定义一个新的访问者实现,并为主层次结构中的每个类编写逻辑。在您的示例中,您可以在对象中打包特定于应用程序的逻辑,并在派生对象中引用这是一种更简单的方法。

答案 1 :(得分:1)

为什么不为应用程序特定的实现使用一组新的层次结构?

class AppBase
{
public:
    virtual ~AppBase() throw();
    virtual void work_with_app() = 0;
};

class Base
{
public:
    Base(AppBase& app) : m_app(app) {}
    virtual ~Base() throw();
protected:
    AppBase& m_app;
};

class DerivedA : public Base { DerivedA(AppBase& app) : Base(app) {} };

class DerivedB : public Base { DerivedA(AppBase& app) : Base(app) {} };

// Application specific implementation :
class AppLuaSpecific : public AppBase
{
public:
    void work_with_app()  { /* Lua app specific */ }
};

这样,您的第一层次结构:BaseDerivedADerivedB可以在不知道AppLuaSpecific中实施的应用专用代码的情况下生存。

答案 2 :(得分:1)

您可以按照以下方式(check it live on Coliru)实施自己的应用专用调度:

#include <iostream>
#include <typeinfo>


struct Base { virtual ~Base() {} };

struct DerivedA : public Base { };

struct DerivedB : public Base { };

namespace AppSpecific
{

template<class F>
void dispatch(const Base& b)
{
    const std::type_info& t = typeid(b);
    if ( t == typeid(DerivedA) )
        F::doit(static_cast<const DerivedA&>(b));
    else if ( t == typeid(DerivedB) )
        F::doit(static_cast<const DerivedB&>(b));
}

struct Foo
{
    static void doit(const DerivedA& da) { std::cout << "Foo(DerivedA)\n"; }
    static void doit(const DerivedB& db) { std::cout << "Foo(DerivedB)\n"; }
};

struct Bar
{
    static void doit(const DerivedA& da) { std::cout << "Bar(DerivedA)\n"; }
    static void doit(const DerivedB& db) { std::cout << "Bar(DerivedB)\n"; }
};

} // namespace AppSpecific

int main()
{
    DerivedA da;
    DerivedB db;

    Base& b1 = da;
    Base& b2 = db;
    AppSpecific::dispatch<AppSpecific::Foo>(b1);
    AppSpecific::dispatch<AppSpecific::Foo>(b2);
    AppSpecific::dispatch<AppSpecific::Bar>(b1);
    AppSpecific::dispatch<AppSpecific::Bar>(b2);
}