转载自:http://www.cnblogs.com/staring-hxs/p/3701742.html
声明( declaration )是告诉编译器某个东西的名称和类型( type ),但略去细节。
下面是声明的例子:
1 extern int x; //对象(object )声明 2 3 size_t numDigits( int number ); //函数声明( function ) 声明 4 5 class Widget; //类( class )声明 6 7 template<typename T> 8 9 class GraphNode; //类模版( template )声明 10 11 12 template<typename T> 13 14 T function( T number1, T number 2); //函数模版声明
定义( definition )是提供编译器一些声明所遗留的细节。
对对象( object )而言,定义是编译器为此对象分配内存。
对函数( function ) 或 函数模版( function template ) 而言,定义是提供代码本体。
对类( class ) 或 类模版( class template )而言,定义列出他们的成员。
下面是定义的例子:
1 int x; //对象的定义 2 3 size_t numDigits( int number ) //函数的定义 4 { 5 //do something 6 return 1; 7 } 8 9 class Widget //类的定义 10 { 11 public: 12 Widget(); 13 ~Widget(); 14 … 15 } 16 17 template< typename T > //类模版的定义 18 class GraphNode 19 { 20 public: 21 GraphNode(); 22 ~GraphNode(); 23 …. 24 } 25 26 template<typename T> 27 T function( T number1, T number 2) //函数模版的定义 28 { 29 return number1 + number2; 30 }
初始化( Initialization )是”给予对象初值”的过程。
对用户自定义类型的对象而言,初始化由构造函数执行。默认( default )构造函数是一个可被调用而不带任何参数,这样的默认构造函数要么没有参数,要么就是每个参数都有缺省值。
1 class A 2 { 3 public: 4 A(); //默认构造函数 5 }; 6 7 class B 8 { 9 public: 10 explicit B( int x=0, bool b=true ); //默认构造函数 11 12 }; 13 14 class C 15 { 16 public: 17 explicit C( int x ); //不是默认构造函数,是带参数的构造函数 18 };
上述的 class B 和 class C的构造函数都被声明为 explicit, 关于 explicit,请参考explicit浅谈。它可用来阻止隐式转换( implicit type conversions )为了防止隐式使用拷贝构造函数,但仍可以进行显示类型转换( explicit type conversions );
explicit浅谈
在C++中,explicit关键字主要用于防止隐式转换,用于修饰构造函数、复制构造函数。
例如有一个类:
1 class A 2 { 3 public: 4 A( int count ) : m_data( count ){} 5 private: 6 int m_data; 7 }; 8 9 int main() 10 { 11 A a = 0; //ok , conver int to A 12 13 a = 10; // 这里是什么操作? 等价与 a.operator=( 10 ); 14 }
1、 A a = 0;
首先编译器( compiler )认为这样写是不符合规矩的,因为 A = A才是正常行为但是它不放弃,通过搜索发现A可以根据一个int构造,同时这个A( int count)没有用explicit修饰过。那么A a=0编译器将自动将整形转为A类对象,实际上等同下面操作
A temp( 0);
A a = temp;
这里需要说明的是 A a = tmp 调用的是拷贝构造函数( copy constructor),虽然clas A中没有,但是通常不写的话,编译器会生成一个成员逐一赋值( memberwise assignment )的拷贝构造函数,底层实现通常会以memcpy进行
2、a = 10;
首先这里同构造函数一样,编译器( compiler ) 无法进行直接操作,等同于代码
a.operator=( 10 );
需要注意的是, a = tmp是调用的赋值运算符( assignment操作 ), 同构造函数一样,我们自己不写, 编译器会生成一个成员逐一赋值(memberwise assignment)操作。
3、fun( A a )
同样, fn(10)也是不对的, 但是"按照惯例", 会有:
A tmp(10);
fn( tmp ) ;
注意:拷贝构造函数的写法只能是 T::T(const T &);
而赋值运算符的写法可以多变,即以任意T为例:
可以有
T &operator = (int n);
也可有
T &operator = (const char *);
当然, 你要确认如此的定义是对T而言有意义.