朋友问一个问题,如下代码,是不是可以通过编译,我看了下,觉得很有意思,故记录下:
Point3D.h
#pragma once
class CPoint3D
{
public:
CPoint3D(void);
public:
~CPoint3D(void);
};
class CPoint3D
{
public:
CPoint3D(void);
public:
~CPoint3D(void);
};
Line3D.h
#pragma once
#include <vector>
class CPoint3D;
class CLine3D
{
public:
CLine3D(void);
public:
~CLine3D(void);
private:
std::vector<CPoint3D> m_Points;
};
#include <vector>
class CPoint3D;
class CLine3D
{
public:
CLine3D(void);
public:
~CLine3D(void);
private:
std::vector<CPoint3D> m_Points;
};
Line3D.cpp
#include "Line3D.h"
#include "Point3D.h"
CLine3D::CLine3D(void)
{
}
CLine3D::~CLine3D(void)
{
}
#include "Point3D.h"
CLine3D::CLine3D(void)
{
}
CLine3D::~CLine3D(void)
{
}
按照一般经验,Line3D的对象实例化的时候,是需要Point3D的对象定义,以决定Line3D自己的内存布局,但是注意这里,在Line3D.h中,只是有CPoint3D的前置申明,没有详细定义,这个编译运行,却是没有问题的。
下面是描述以上一般情况的代码
一般情况
#pragma once
class CPoint3D;
class CLine3D
{
public:
CLine3D(void);
public:
~CLine3D(void);
private:
// 使用指针的话,编译器知道指针的内存布局,故pass
// 但是使用CPoint3D m_Point的话,会报编译错误,说类找不到。
CPoint3D * m_Point;
};
class CPoint3D;
class CLine3D
{
public:
CLine3D(void);
public:
~CLine3D(void);
private:
// 使用指针的话,编译器知道指针的内存布局,故pass
// 但是使用CPoint3D m_Point的话,会报编译错误,说类找不到。
CPoint3D * m_Point;
};
一般的C++程序员都能理解上面一般情况的代码,但是对于开始std::vector的使用中的情况却不甚明了了。这样难怪我搞了3年多C++的朋友也会问这个问题。
其实问题很简单,大家翻翻std::vector的实现代码就很明了了。这个模板使用的是堆上的对象数组的方式来管理模板参数对象,std::vector本身的实现中,需要的也是对象指针的定义,由编译器自己计算的,不需要对象本身的定义,故只要在实现文件中包含相关的类定义就可以了。
还有人可能认为,在头文件包含多省事,还少写个类的前置申明。但是我认为,一个优秀的C++工程师,要有优秀的习惯,头文件要遵循无依赖原则。
今年是2010年第一天,祝各位新年快乐。