02 c++的封装性 (构造和析构)
封装性:
关键字:public private protected
破坏封装:友元函数 friend
实现数据的隐藏:class类 默认是私有,结构体默认是公有。
类和对象:(定义类的注意事项)
- 在类体中不允许对所定义的数据成员进行初始化;
- 类中的数据成员的类型可以使任意的:
- 包含整形、浮点型、字符型、数组、指针和引用等;
- 另一个类的对象,可以作该类的成员;
- 自身类的对象不可以做该类的成员,但自身的对象的指针和引用可以作该类的成员;
- 自身类的指针或引用,可以作该类的成员;
- 当另一个类的对象做为该类的成员时,如果另一个类的定义在后,需要提前说明;
- 一般在类体内先说明用户感兴趣的公有成员,再说明私有成员;
- 习惯将类定义的说明部分或者整个定义部分(包含实现部分)放在一个头文件中;
构造函数:
定义:
- 在每次创建对象时由系统调用,没有任何返回值(包括void)可以用来为某些成员变量设置初始值。
目的:
- 为了增加对象初始化自己的能力
作用:
- 用来在创建对象时初始化对象,多和new运算符一起在创建对象时使用。
- 一个类可以有多个构造函数,根据参数的不同和参数类型的不同来区分(构造函数的重载)
- 构造函数可以包含其他的函数,但是为了保证程序的清晰,一般只在构造函数中加入函数的声明。
特点:
- 是一种特殊的成员函数
- 不用用户调用,在创建对象时调用
- 名字和类名同名
- 没有任何类型,没有返回值
- 必须是公共的,否则无法生成对象
- 只负责为自己的类构造对象
- 每个创建一个class系统会自动调用一个构造函数,但是如果用户自己定义构造函数,系统就不会默认提供
下面是几种不同的构造函数:
常见的构造函数:
1 .h: 2 3 explicit MainWindow(QWidget *parent = 0); 4 5 .c: 6 7 MainWindow::MainWindow(QWidget *parent) : 8 QMainWindow(parent), 9 ui(new Ui::MainWindow) 10 { 11 ui->setupUi(this); 12 } 13 14 .h: 15 16 explicit Widget(QWidget *parent = 0); 17 18 .c: 19 20 Widget::Widget(QWidget *parent) : 21 QWidget(parent), 22 ui(new Ui::Widget) 23 { 24 ui->setupUi(this); 25 }
带参数的构造函数:
默认的构造函数没有任何参数,但如果需要,构造函数也可以带有参数。这样在创建对象时就会给对象赋初始值。
例子:
1 #include <iostream> 2 3 using namespace std; 4 5 class Line 6 { 7 public: 8 void setLength( double len ); 9 double getLength( void ); 10 Line(double len); // 这是构造函数 11 12 private: 13 double length; 14 }; 15 16 // 成员函数定义,包括构造函数 17 Line::Line( double len) 18 { 19 cout << "Object is being created, length = " << len << endl; 20 length = len; 21 } 22 23 void Line::setLength( double len ) 24 { 25 length = len; 26 } 27 28 double Line::getLength( void ) 29 { 30 return length; 31 } 32 // 程序的主函数 33 int main( ) 34 { 35 Line line(10.0); 36 37 // 获取默认设置的长度 38 cout << "Length of line : " << line.getLength() <<endl; 39 // 再次设置长度 40 line.setLength(6.0); 41 cout << "Length of line : " << line.getLength() <<endl; 42 43 return 0; 44 }
在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换。
使用初始化列表来初始化字段:
下面两种写法等价:
Line::Line( double len): length(len) { cout << "Object is being created, length = " << len << endl; } Line::Line( double len) { length = len; cout << "Object is being created, length = " << len << endl; }
析构函数:
- 它会在每次删除所创建的对象时执行。析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
特点:
- 和构造函数一样,函数名称不可以自定义 没有返回类型 没有参数 不可以重载 由系统直接调用
作用:
- 在撤销对象占用的内存前完成一些清理工作,使这部分内存可以被程序分配给新对象使用
- 执行用户希望在最后一次使用对象后执行的任何操作
- 如果用户没有定义,系统会自动生成(这个析构函数不会做任何操作)
析构函数执行:
- 函数定义的自动局部对象,在函数调用结束,对象被释放前调用
- static局部对象,在main函数或调用exit函数结束程序时调用局部对象的析构函数
- 全局对象,在函数离开作用域时调用全局对象的析构函数
- 使用new创建的对象,调用delete时释放该函数,先调用对象的析构函数(需要自己定义)
例如:
1 #include <iostream> 2 3 using namespace std; 4 5 class Line 6 { 7 public: 8 void setLength( double len ); 9 double getLength( void ); 10 Line(); // 这是构造函数声明 11 ~Line(); // 这是析构函数声明 12 13 private: 14 double length; 15 }; 16 17 // 成员函数定义,包括构造函数 18 Line::Line(void) 19 { 20 cout << "Object is being created" << endl; 21 } 22 Line::~Line(void) 23 { 24 cout << "Object is being deleted" << endl; 25 } 26 27 void Line::setLength( double len ) 28 { 29 length = len; 30 } 31 32 double Line::getLength( void ) 33 { 34 return length; 35 } 36 // 程序的主函数 37 int main( ) 38 { 39 Line line; 40 41 // 设置长度 42 line.setLength(6.0); 43 cout << "Length of line : " << line.getLength() <<endl; 44 45 return 0; 46 }
总结:
- 一般初始化工作放在构造函数中,清除工作放在析构函数中
- 创建对象调用构造函数
- 对象消亡调用析构函数
身体是1,财富·名利·是0,没有1有再多的0都没有用!!