C++”前置声明“那些事儿(二)

2014-11-24 02:44:46 · 作者: · 浏览: 4
h
#include "stdafx.h"
#include "XYZ.h"
class AImpl
{
public:
AImpl();
~AImpl();
X* getX();
Y* getY();
Z* getZ();
void doSth();
private:
X* x;
Y* y;
Z* z;
};
//AImpl.cpp
#include "stdafx.h"
#include "Aimpl.h"
#include
AImpl::AImpl(){
x = new X();
y = new Y();
z = new Z();
}
AImpl::~AImpl(){
if (x)
{
delete x;
}
if (y)
{
delete y;
}
if (z)
{
delete z;
}
}
X* AImpl::getX(){
return x;
}
Y* AImpl::getY(){
return y;
}
Z* AImpl::getZ(){
return z;
}
void AImpl::doSth(){
x->Print();
y->Print();
z->Print();
}
// A.h
#include "stdafx.h"
#include
class AImpl;
class X;
class Y;
class Z;
class A
{
public:
A();
X* getX();
Y* getY();
Z* getZ();
void doSth();
private:
std::shared_ptr pImpl;
};
//A.cpp
#include "stdafx.h"
#include "A.h"
#include "Aimpl.h"
A::A(){
pImpl = std::shared_ptr(new AImpl());
}
X* A::getX(){
return pImpl->getX();
}
Y* A::getY(){
return pImpl->getY();
}
Z* A::getZ(){
return pImpl->getZ();
}
void A::doSth(){
pImpl->doSth();
}
//PreDeclaration.cpp
#include "stdafx.h"
#include "A.h"
int main()
{
A a;
a.doSth();
return 0;
}
在这个例子中,A.h是提供给客户使用的头文件,在该文件中定义了class A,其中只含有一个指针成员(pImpl),指向其实现类(AImpl)。在这样的设计之下,使用class A的客户端就完全与X、Y、Z以及AImpl的实现细节分离了,同时实现了“实现细节”的隐藏,这样,无论这些classes的任何实现修改都不需要A的客户端重新编译。
使用“前置声明”的注意事项
(1)在前置声明时,我们只能使用的就是类的指针和引用,自然也就不能调用对象的方法了!
像我们这样前置声明类A:
class A;
是一种不完整的声明,只要类B中没有执行"需要了解类A的大小或者成员"的操作,则这样的不完整声明允许声明指向A的指针和引用。
而在前一个代码中的语句
A a;
是需要了解A的大小的,不然是不可能知道如果给类B分配内存大小的,因此不完整的前置声明就不行,必须要包含A.h来获得类A的大小,同时也要重新编译类B。
再回到前面的问题,使用前置声明只允许的声明是指针或引用的一个原因是:只要这个声明没有执行“需要了解类A的大小或者成员”的操作就可以了,所以声明成指针或引用是没有“执行需要了解类A的大小或者成员的操作”的。
我们将上面这个例子的A.cpp稍作修改:
[cpp]
//A.cpp
#include "stdafx.h"
#include "A.h"
#include "Aimpl.h"
A::A(){
pImpl = std::shared_ptr(new AImpl());
}
X* A::getX(){
return pImpl->getX();
}
Y* A::getY(){
return pImpl->getY();
}
Z* A::getZ(){
return pImpl->getZ();
}
void A::doSth(){
//pImpl->doSth();
getX()->Print();
getY()->Print();
getZ()->Print();
}