这是一个设计缺陷吗?

时间:2009-11-11 18:02:44

标签: c++ design-patterns

考虑两个班级

class A{
     public:
       A(){
       }
       ~A(){
       }
};


class AImpl : public A{
      public:
         AImpl(){
             a = new AInternal();
         }
         AImpl(AInternal *a){
             this->_a = a;
         }
         ~AImpl(){
             if(a){
                delete a;
                a = null;
             }
         }
       private:
             AInternal *a;
};

我正在尝试隐藏 AInternal的实现,并且只显示 A的界面。我在这里看到的两件事

  1. A级完全是空的。
  2. 隐藏基本上是通过继承来实现的。我必须实际使用从A到AImpl的向下转换和向上转换,反之亦然。
  3. 这是一个很好的设计吗?由于缺乏设计经验,我看不出它的缺陷以及它为什么不好?

6 个答案:

答案 0 :(得分:18)

你使用3个类过度复杂化了。我认为你要找的是pimpl idiom

答案 1 :(得分:1)

  

我试图隐藏AInternal的实现并只公开A的接口。

我认为你正在尝试做factory之类的事情。

以下是一个例子:

 class IA {                                               
 public:
         IA() {}
         virtual ~IA() {}
         virtual void dosth() =0;
 };

 class Factory {
 private:
         class A : public IA {
         public:
                 A () {}
                 virtual ~A() {}

                 void dosth() { cout << "Hello World"; }
         };

 public:
         Factory () {}
         virtual ~Factory() {}

         IA*newA() { return new A; }
 };

和Factory类的用法:

Factory f;
IA*a = f.newA();
a->dosth();
return 0;

答案 2 :(得分:0)

IMO AInternal毫无意义。无论你在那里做什么,都应该在AImpl中完成。否则,可以在C ++中执行此操作。

答案 3 :(得分:0)

代码相当迟钝,所以我会担心在未来六个月内维护它。

答案 4 :(得分:0)

如果你打算这样做,那么析构函数~A必须是virtual

答案 5 :(得分:0)

您似乎将两种常见的设计功能结合在一起:

1)AInternal是一个“pimpl”。它提供了更好的封装,例如,如果您需要向AInternal添加新字段,那么AImpl的大小不会改变。没关系。

2)A是用于表示接口的基类。既然你谈到了向上转换和向下转换,我假设你想要动态多态,这意味着你将拥有传递指针或引用A的函数,并且在运行时,referands实际上是AImpl类型。这也没关系,除了A的析构函数应该是虚拟的和公共的,或非虚拟的和受保护的。

我发现此代码没有其他设计问题。当然,您需要实际定义接口A,方法是在AImpl中添加一些纯虚拟成员函数。假设您打算这样做,那么使用空基类来实现Java中的接口(如果您了解Java)是没有错的。通常你会有一些工厂创建AImpl对象,并通过指针或对A的引用返回它们(因此,将它们向上转换)。如果客户端代码将直接创建AImpl对象,那么这也可能没问题,实际上您可能根本不需要动态多态。你可以改为进入模板。

我不明白为什么你不得不贬低(也就是说,将A *强制转换为AImpl *)。这通常是坏消息。因此,您的设计中可能存在一些问题,只能通过向我们展示更多类的定义以及实际使用A和AImpl的客户端代码来揭示。