考虑两个班级
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的界面。我在这里看到的两件事
这是一个很好的设计吗?由于缺乏设计经验,我看不出它的缺陷以及它为什么不好?
答案 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的客户端代码来揭示。