对于一个类A来说,有一个构造函数A(int num1,int num2);
我们在定义一个对象的时候可以这样初始化:
1、A a1(1,2); 隐式调用构造函数
2、A a2 = A(1,2); 显式调用构造函数,先创建个临时对象,再将临时对象复制给a2
3、A *a3 = new A(1,2) 用指针去调用对象的内存,对象名并不存在!
若是 4、A a4; 则不正确,这将调用一个默认的构造函数,当程序自定义了一个构造函数之后,默认的将被屏蔽,为此解决办法:
--------在类里面定义个默认的构造函数 :A();
--------在上述自定义的构造函数传入默认参数:A(int num1=1,int num2=2);
这样就能A a4;去定义一个对象了,而不是A a4(); 这是定义一个函数!
对于上述的几种定义对象A a;的方法之后: a = A(3,4); 这并不是对象的初始化,而是赋值,在这里,调用构造函数创建了一个临时的对象(C++里面的临时变量是看不见的),然后将临时对象的赋值给了对象a;临时对象随着这语句的调用栈将销毁。 若是将一个对象赋值给另一个对象,如 a = a1; 这句话调用的将是重载赋值运算符函数!
这在某些智能指针的应用方面,如unique_ptr :
unique_ptr<string> pu1(new string ("hello world")); //隐式调用构造函数 unique_ptr<string> pu2; pu2 = pu1; // #1 not allowed unique_ptr<string> pu3; pu3 = unique_ptr<string>(new string ("You")); // #2 allowed
对于 #1 pu1和pu2的生存周期是一样的,通过赋值,将pu2的指向pu1指向的内容,而pu1将会变成悬挂指针,这编译器是不允许的。
对于#2 给pu3赋值,pu3将指向一个临时变量所创建的堆地址,临时变量在执行#2语句之后就销毁了,所以不必担心悬挂指针的出现。 有可能你会发现其实#2 就是这样的语句,
unique_ptr<string> pu3 = unique_ptr<string>(new string ("You")); //显式调用构造函数
更多智能指针问题,以后会介绍
对于一个参数的构造函数来说,我们需要知道,这个函数可以当做转换函数!如B类,它的构造函数是B(int num); 我们在定义这个类的对象的时候:
#1、B b1(2);
#2、B b2 = B(2);
#3、B *b3 = new B(3);
在这里还可以:#4 B b = 4; 这样来定义一个对象! 这里创建了个临时对象,然后将4作为初始化值,然后将这个临时对象复制给b对象! 这一过程称为隐式类型转换,是自动进行的,所以不需要显式强转!好比#2就是显式强转。有的人会发现,为什么上述的只能指针的显示调用构造函数不能写成:
unique_ptr<string> pu3 = new string ("You"); // not allowed
这是因为只能指针的内部实现的构造函数前面有个关键字:explicit,这个关键字就是防止自动类型的转换,这样子
B b = 4; 就不被允许了!而是需要显示的转换 #1 #2 #3 都是可以的或者 B b = (B)4;显式强转。
既然有别的类型向类的类型转换,那么能不能类的类型自动转为别的类型?如 int num = a;(这里的a是个对象),在类里面重载int就行了:operator int ();
这里注意的是重载多个类型注意了二义性问题,为避免二义性的问题可以int num = (int) a;