今天在看Leveldb源码的时候,发现作者使用了很多前置声明,这个语法之前关注的不是很多,今天稍微总结下。
主要参考了下面文章:
[关于C++中的前置声明]
什么时候用
- 一般是用头文件来声明要使用的新类型,但是当两个头文件形成环的时候可以使用类的前置声明来破除环。
- 我看leveldb源码的时候,作者大量使用前置声明,并不是因为这个原因,忘了在哪看到过,在此处使用前置声明的原因应该是:前置 引用声明比头文件节省了大量的代码长度。
- 但是,前置引用声明使用的时候有很大的限制就是只能使用类的引用或者指针,因为前置声明只是声明,不是类的定义,没有办法去定义对象,自然也就不能访问类的方法。
- 感觉这样做,头文件可以清晰一点。把实现放到源文件里面去。
代码
先给出错误的示范:考虑写一个四则运算的运算符类,以及操作数类。
// Opnd.h
#ifndef OPND_H_
#define OPND_H_
class Opnd {
public:
Opnd(){ a_ = 0; }
Opnd( int x ) : a_(x) {}
int get_a() const { return a_; }
private:
int a_;
};
#endif
// Optr.h
#ifndef OPTR_H_
#define OPTR_H_
#include <cassert>
class Opnd; // 前置声明
class Optr{
public:
Optr( char c = '+' ) : op(c) {}
int compute( const Opnd& left, const Opnd& right ){ // 正确使用
int ans = 0;
int lvalue = left.get_a();// 错误使用,前置声明只是声明,不是定义,所以不能使用类方法
int right = right.get_a();// 错误使用
switch( op ){
case '+' : ans = lvalue + rvalue; break;
case '-' : ans = lvalue - rvalue; break;
case '*' : ans = lvalue * rvalue; break;
case '/' : assert(right != 0); ans = lvalue / rvalue; break;
}
return ans;
}
private:
char op;
};
#endif
下面给出正确的示范:
// Opnd.h
#ifndef OPND_H_
#define OPND_H_
class Opnd {
public:
Opnd(){ a_ = 0; }
Opnd( int x ) : a_(x) {}
int get_a() const { return a_; }
private:
int a_;
};
// Optr.h
#ifndef OPTR_H_
#define OPTR_H_
#include <cassert>
class Opnd; // 前置声明
class Optr{
public:
Optr( char c = '+' ) : op(c) {}
int compute( const Opnd& left, const Opnd& right ); // 使用正确
private:
char op;
};
#endif
实现放到源文件里面去。
// Optr.cpp
#include <cassert>
#include "Optr.h"
#include "Opnd.h"
int Optr::compute( const Opnd& left, const Opnd& right ){
int ans = 0;
int lvalue = left.get_a();
int rvalue = right.get_a();
switch( op ){
case '+' : ans = lvalue + rvalue; break;
case '-' : ans = lvalue - rvalue; break;
case '*' : ans = lvalue * rvalue; break;
case '/' : assert(rvalue != 0); ans = lvalue / rvalue; break;
}
return ans;
}
// main.cpp
#include "Optr.h"
#include "Opnd.h"
#include <iostream>
int main( void ){
Opnd opnd1(3);
Opnd opnd2(4);
Optr opt('+');
std::cout << opt.compute( opnd1, opnd2 ) << std::endl;
return 0;
}