C++前置声明

以个人理解,C++的前置声明的意思是在类定义之前对其进行声明。它在现实编程的场景中可以解决很多问题。比如解决两个类相互依赖的问题,降低类之间的编译依存关系等等。

实际场景

我们分别定义一个锁(Lock)和钥匙(Key)的类(默认一把钥匙只能开一把锁,一把锁只能被一把钥匙打开)。代码如下:
Lock.hpp

1
2
3
4
5
6
7
8
#include "Key.hpp"
class Lock {
public:
Lock();
virtual ~Lock();
private:
Key m_key;
}

Key.hpp

1
2
3
4
5
6
7
8
#include "Lock.hpp"
class Key {
public:
Key();
virtual ~Key();
private:
m_lock;
}

这个时候出现了两个类相互包含的情况,因为在编译Lock.cpp的时候,我们需要去查看Key的定义,于是去定义Key,在Key中需要Lock的定义,于是又去构造Lock,这样下去,就出现了一个无限循环包含的情况,有些编译器会直接编译错误,而其他编译器会无限包含下去。
这该怎么办呢?有办法,C++为我们提供了前置声明。前置声明是什么?就这个例子来讲,我们要造一把锁,光有锁不行啊,我们还得有能打开这把锁的钥匙。但是锁还没有造好,总不能先打造钥匙吧,钥匙的形状我定了,改天在造。先把锁造好,造锁的时候我要先给要是留一个位置,等锁造好了,我再决定造什么样的钥匙。前置声明就是我在声明一个类(Lock)的时候,用到了另外一个类(Key)的定义,但是Key还没定义呢,而且我先不需要Key的定义,只需要直到Key是一个类就好了。那好,我就先声明类Key,告诉编译器Key是一个类(不需要包含Key.hpp)

1
class Key;

然后在Lock中用到Key的时候,都用指针或者引用代替(因为指针是固定大小的,但Key的大小只有知道了Key的定义才能确定)。然后上面的代码就可以改造为如下:

Lock.hpp

1
2
3
4
5
6
7
8
class Key;
class Lock{
private:
Key *mp_key;
public:
Lock();
virtual ~Lock();
};

Key.hpp

1
2
3
4
5
6
7
8
class Lock;
class Key {
private:
Lock* mp_lock;
public:
Key();
virtual ~Key();
}

前置声明注意的问题

必须使用前置声明的指针或引用形式

在需要使用前置声明的文件中,不可以使用类的定义式,因为类的定义式只有在类定义之后才能获取,这个时候类还没有定义,所以会出错。另一个类在构造的时候编译器是需要计算该对象所占的字节的大小给其分配内存的,但是如果使用类的定义式,这个时候类还未定义,所以无法计算其大小,所以只能使用指针或者引用的形式进行引用。

避免在Lock中使用Key的方法

避免在Key定义之前调用Key的析构函数