原文链接来自席位网络:http://www.xevc.com/%e6%b7%b1%e5%85%a5%e8%a7%a3%e6%9e%90c%e7%b1%bb%e5%af%b9%e8%b1%a1%e7%9a%84%e8%b5%8b%e5%80%bc%e5%a4%8d%e5%88%b6%e4%b8%8e%e7%b1%bb%e5%9e%8b%e8%bd%ac%e6%8d%a2/
对象的转换是调用转换构造函数。
对象的初始化其调用构造函数。
先说类的构造函数的分类:
默认构造函数:没有参数
转换构造函数:参数为非本类类型
复制构造函数:参数为本类对象的引用
普通构造函数:至少一个参数
以下面定义的类为例
class A{public:
A() { cout<<”默认构造函数”<<endl; } A(int a) { cout<<”转换构造函数”<<endl; } A(int a, int b) { cout<<”普通构造函数”<<endl; } A(A & a) { cout<<”复制构造函数”<<endl; } A & operator = (A & a) { cout<<”赋值运算符重载”<<endl; return *this; } ~A() { cout<<”析构函数”<<endl; } }; A getA(A a) { return a; } int main(int argc,char **argv) { A a1, a2; a2 = getA(a1); return 0; } |
初始化、赋值、复制经常不容易区分开。其实很简单,赋值是调用operator=函数,而复制是用复制构造函数。构造函数只会在初始化时被自动调用。而赋值函数则只会在赋值时被调用,注意,初始化是在声明对象时就给它赋予初值,而赋值是在声明对象之后被手动调用的。对于一个对象,即便我们没有显示的初始化,也会调用默认的构造函数进行初始化。如下面八条初始化语句:
既然讲清了初始化。那么再来说赋值与复制。
A a1,a2;
a1 = a2;// 这是赋值,其实是a1.operator = (a2)
A a3 = a2;//用复制构造函数对a3进行初始化,也称为将a2复制为a3。
A a4 = 5;语句其实质是A a4 = A(5)或者A a4(5)
A a5 = a4语句实质是A a5 = Test(a4)或者A a5(a4),调用的是默认的复制构造函数
所有只有一个参数的构造函数都叫单参数构造函数,这类构造函数可能出现像赋值一样的隐匿调用,从而导致自动类型转换。加上explicit关键字可以避免这个问题。在构造函数的声明前加上explicit关键字,则该构造函数不能被隐匿调用。
类型转换运算
在大多数情况下,类类型的转换都可以通过类型转换构造函数和重载类型转换函数来完成
如下面一个类
class Test{public:
Test(int a) { m_a = a; } operator double() { return (double)m_a; } private: int m_a; }; |
由于我们定义了一个类型转换构造函数Test(int a)
所以我们方便的将int型转换为Test型。
int i = 4;
Test t = i; //隐匿调用转换构造函数Test(int a)
double d = t; // 调用类型转换函数operator double()
但假如这个类型转换构造函数是以“explicit Test(int a)”方式声明的,则我们不能通过隐匿调用转换构造函数的方式来进行类型转换,我们需要这样调用:
Int i = 4;
Test t(i); //显示调用转换构造函数explicit Test(int a)
如果没有转换构造函数或者类型转换函数的支持,可以通过强制类型转换来完成
另外要注意const_cast关键字的用法,它设置或除去变量的常量性,类型必须是引用或指针。如
const int ca = 4;
Int & ra = ca;则是错的,而int &ra = const_cast<int &>(ca);则正确。