C++构造函数
2016-07-14 18:19
441 查看
一. 构造函数
1. 每个类都分别定义了它的对象被初始化的方式,通过一个或几个特殊的函数来控制其对象的初始化过程,这些函数叫做构造函数。构造函数的任务是初始化类对象的数据成员。
2.
在main函数Test类实例化一个对象Test T1,编译系统为对象的数据成员data分配空间,并调用构造函数初始化数据成员。在构造函数中,Test应该为Test(Test*const this),this指针指向当前对象。
一. 构造函数种类
1. 无参构造函数
(1) 如果在一个类中没有定义任何构造函数,编译器会自动生成一个默认无参构造函数初始化数据成员。
(2) 如果定义了一个构造函数,编译器不会自动生成默认构造函数。而如果需要默认构造函数,需要显示的定义默认构造函数。但要注意二义性的问题。当定义了默认构造函数,并且重载了一个带默认参数的构造函数,如下:
编译后,出现如下错误:
没有传递参数时,系统默认又两种选择,一种是调用默认构造函数,另一种是调用带参构造函数并传递默认参数。这样就造成了二义性。
2. 一般构造函数
构造函数允许重载。除了上述的无参构造还可以定义一些参数进行传递的构造函数。
3. 拷贝构造函数
如果一个构造函数的第一个参数是自身类型的引用,且任何额外参数都有默认值,此构造函数为拷贝构造函数。
(1) 如果类中为定义一个拷贝构造函数,则编译器会自动生成一个拷贝构造函数。
运行结果如下:
(2) 每个成员的类型决定其如何拷贝:对于类类型的数据成员,会使用其拷贝构造函数进行拷贝;对于内置类型成员则直接拷贝。拷贝构造函数会将数组元素逐一拷贝。
其结果为:
注:Test类的对象在对MyClass类类型成员无论是调用构造函数还是拷贝构造函数时,一定要有MyClass类的对象去调用。 也就是Test(intdata, char ch, int d, int * a):myclass(d, a)和Test(MyClass my):myclass(my),因为MyClass类成员的数据是私有的,Test类无法访问。
(3) 拷贝构造函数不仅在用 ‘ = ‘ 定义变量时会发生。下列情况也会发生。
a. 将一个对象作为实参传递个一个非引用类型的形参。
b. 从一个返回类型为非引用的类型函数返回一个对象。
(4) 为什么拷贝构造函数的参数要为引用?如果不为引用,例如Test(const Test T),相当于把对象作为参数进行传递,需要调用拷贝构造,然后发现又不是引用,就一直执行这个拷贝构造函数。
4. 转换构造函数
(1) 如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制。这种构造函数称为转换构造函数。
在100为整型变量,在赋值时,构造了一个临时的ConvertingConstructor对象,然后该对象调用ConvertingConstructor(int IntData = 0)构造函数,形参的值为100,然后将该临时对象赋给coverting对象,完成隐式类型转换。
若要将一个类的对象赋值给一个内置类型,需要一下函数定义:
type可以为任意类型(void除外)。不能转化为数组或者函数类型,但可以为指针和函数指针类型。
运行结果如下:
(2) 抑制构造函数定义的隐式转换。
通过将构造函数声明为explicit来抑制。关键字explicit只对一个实参的构造函数有效。只能在类内声明构造函数时使用该关键字,在类外部定义不应重复。
1. 每个类都分别定义了它的对象被初始化的方式,通过一个或几个特殊的函数来控制其对象的初始化过程,这些函数叫做构造函数。构造函数的任务是初始化类对象的数据成员。
2.
#include <iostream> using namespace std; class Test { private: int data; public: Test () { // 构造函数,与类名同名 data = 0; } };
在main函数Test类实例化一个对象Test T1,编译系统为对象的数据成员data分配空间,并调用构造函数初始化数据成员。在构造函数中,Test应该为Test(Test*const this),this指针指向当前对象。
一. 构造函数种类
1. 无参构造函数
(1) 如果在一个类中没有定义任何构造函数,编译器会自动生成一个默认无参构造函数初始化数据成员。
(2) 如果定义了一个构造函数,编译器不会自动生成默认构造函数。而如果需要默认构造函数,需要显示的定义默认构造函数。但要注意二义性的问题。当定义了默认构造函数,并且重载了一个带默认参数的构造函数,如下:
class Test { private: int data; public: Test () { data = 0; } Test (int d = 0) { data = d; } }; int main(void) { Test T; return 0; };
编译后,出现如下错误:
Class.cpp:19:10: error: call of overloaded ‘Test()’ is ambiguous
没有传递参数时,系统默认又两种选择,一种是调用默认构造函数,另一种是调用带参构造函数并传递默认参数。这样就造成了二义性。
2. 一般构造函数
构造函数允许重载。除了上述的无参构造还可以定义一些参数进行传递的构造函数。
class Test { private: int data; public: Test () { data = 0; cout << "Constructor" << endl; } Test(int data) { this -> data = data; } };
3. 拷贝构造函数
如果一个构造函数的第一个参数是自身类型的引用,且任何额外参数都有默认值,此构造函数为拷贝构造函数。
Test(const Test & T2) { Data = T2.data; }
(1) 如果类中为定义一个拷贝构造函数,则编译器会自动生成一个拷贝构造函数。
class Test { private: int data; char ch; public: Test(int data = 0, char ch = 'a') { this -> data = data; this -> ch = ch; cout << "Constructor" << endl; } void Print() { cout << data << ' ' << ch; cout << endl; } }; int main(void) { Test T; Test T1 = T; T1.Print(); return 0; }
运行结果如下:
Constructor 0 a
(2) 每个成员的类型决定其如何拷贝:对于类类型的数据成员,会使用其拷贝构造函数进行拷贝;对于内置类型成员则直接拷贝。拷贝构造函数会将数组元素逐一拷贝。
class MyClass { private: int data; int array[3]; public: MyClass(int data = 0, int * array = NULL) { this -> data = data; this -> array[0] = array[0]; this -> array[1] = array[1]; this -> array[2] = array[2]; cout << "MyClass Constructor " << endl; } MyClass(const MyClass& myclass) { this -> data = myclass.data; this -> array[0] = myclass.array[0]; this -> array[1] = myclass.array[1]; this -> array[2] = myclass.array[2]; cout << "MyClass copy Constructor " << endl; } void Print() { cout << "MyClass Data is " << data << endl; cout << "MyClass Array is "; int i = 0; for ( i = 0; i < 3; i++) { cout << array[i] << ' '; } cout << endl; } }; class Test { private: int data; char ch; MyClass myclass; // MyClass类对象 public: Test(int data, char ch, int d, int * a):myclass(d, a) { this -> data = data; this -> ch = ch; cout << "Test Constructor" << endl; } Test(MyClass my):myclass(my) { // 调用MyClass对象的拷贝构造函数 } void Print() { cout << "Test data is "; cout << data << ' ' << ch; cout << endl; myclass.Print(); } }; int main(void) { int array[3] = {1, 2, 3}; Test T(1, 'x',100, array); Test copy = T; copy.Print(); return 0; }
其结果为:
MyClass Constructor Test Constructor MyClass copy Constructor Test data is 1 x MyClass Data is 100 MyClass Array is 1 2 3
注:Test类的对象在对MyClass类类型成员无论是调用构造函数还是拷贝构造函数时,一定要有MyClass类的对象去调用。 也就是Test(intdata, char ch, int d, int * a):myclass(d, a)和Test(MyClass my):myclass(my),因为MyClass类成员的数据是私有的,Test类无法访问。
(3) 拷贝构造函数不仅在用 ‘ = ‘ 定义变量时会发生。下列情况也会发生。
a. 将一个对象作为实参传递个一个非引用类型的形参。
b. 从一个返回类型为非引用的类型函数返回一个对象。
(4) 为什么拷贝构造函数的参数要为引用?如果不为引用,例如Test(const Test T),相当于把对象作为参数进行传递,需要调用拷贝构造,然后发现又不是引用,就一直执行这个拷贝构造函数。
4. 转换构造函数
(1) 如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制。这种构造函数称为转换构造函数。
class ConvertingConstructor { public: ConvertingConstructor(int IntData = 0) { this -> IntData = IntData; cout << "Constructor " << endl; } void Print() { cout << IntData << ' ' << DoubleData; cout << endl; } private: int IntData; double DoubleData; }; int main(void) { ConvertingConstructor coveting = 100; coveting.Print(); return 0; }结果如下:
Constructor 100 0
在100为整型变量,在赋值时,构造了一个临时的ConvertingConstructor对象,然后该对象调用ConvertingConstructor(int IntData = 0)构造函数,形参的值为100,然后将该临时对象赋给coverting对象,完成隐式类型转换。
若要将一个类的对象赋值给一个内置类型,需要一下函数定义:
operator type() const; // type为要转换的类型。
type可以为任意类型(void除外)。不能转化为数组或者函数类型,但可以为指针和函数指针类型。
class ConvertingConstructor { public: ConvertingConstructor(int IntData = 0, double DoubleData = 0.0) { this -> IntData = IntData; this -> DoubleData = DoubleData; cout << "Constructor " << endl; } operator int() const { return IntData; } void Print() { cout << IntData << ' ' << DoubleData; cout << endl; } ~ConvertingConstructor() { cout << "Destructor" << endl; } private: int IntData; double DoubleData; }; int main(void) { ConvertingConstructor coverting(100, 3.13124); int IntData = coverting; cout << IntData; cout << endl; return 0;
运行结果如下:
Constructor 100 Destructor
(2) 抑制构造函数定义的隐式转换。
通过将构造函数声明为explicit来抑制。关键字explicit只对一个实参的构造函数有效。只能在类内声明构造函数时使用该关键字,在类外部定义不应重复。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C++的template模板中class与typename关键字的区别分析
- C与C++之间相互调用实例方法讲解