类的封装性和信息隐蔽
私有实现:类中被操作的数据是私有的,实现细节对于用户而言是隐蔽的。
类的共用接口 和私有实现的分离形成了信息隐蔽
类声明和成员函数定义的分离
在头文件中进行类的声明:
//file name:student.h
#pragma once
class student
{
public:
void display();
private:
int num;
char name[20];
char sex;
};
main.h:
#include <iostream>
#include"student.h"
using namespace std;
int main()
{
std::cout << "Hello World!\n";
}
void student:: display()
{
cin >> num >>name>>sex;
}
利用#include"stdio.h"调用自定义的头文件,值得注意的是,此处利用cin为a[20]赋值,若字符串长度超过20,则截断。
进行编译时,C++编译系统会分别对两个源文件进行编译,得到两个目标程序main.obj和student.obj,然后将它们和其他资源连接起来,形成可执行exe文件。
实际工作中,并非将一个类声明为一个头文件,而是将若干个功能近似的类声明集中在一起,形成类库,包括 C++编译系统提供的标准类库及自定义类库。
接下来让我们对类和对象做进一步的讨论。
构造函数
对象的初始化 :建立对象时需对其中数据成员赋值,否则其值是不可预知的。
注意:数据成员不能在声明类的时候进行初始化,因为类是抽象的,而对象可以,因为对象为实体,前提是成员为公用的。
可以利用构造函数在声明类时进行数据的初始化,作为一种特殊成员函数,在建立对象时自动执行,不需要用户进行调用,其函数名必须和类名一致,且不具有任何类型和返回值。
例如:
class stu {
public:
stu()
{
a = 1;
b = 2;
}
private:
int a;
int b;
};
也可以在类中进行构造函数的声明,于类外定义该函数:
class stu {
public:
stu();
private:
int a;
int b;
};
stu::stu()
{
a = 1;
b = 2;
}
如果用户未定义构造函数,系统会自动生成一个构造函数,只是该函数的函数体为空,也无参数,不执行初始化操作。
另外,也可以使用带参数的构造函数去声明带参数的构造函数:
void student:: display()
{
stu st(1, 2, 3);
}
class stu {
public:
stu(int n,int m,int y);
private:
int a;
int b;
int c;
};
stu::stu(int n,int m,int y)
{
a = n;
b = m;
c = y;
}
可知,构造函数所对应的实参在定义对象时给定。
构造函数的重载
在一个类中可以定义多个构造函数,以便对类对象提供不同的初始化的方法,供用户选用。系统通过其参数的个数或参数类型的不同进行筛选。
默认构造函数: 调用时不必给出实参的构造函数,且一个类只能有一个默认构造函数。
析构函数
它的作用和构造函数相反,其名字是类名前面加一个‘ ~ ’符号。
当对象生命周期结束时,会自动执行析构函数:
1.在函数中定义了一个对象,当此函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。
2.static局部对象在函数调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用static局部对象的析构函数。
3.如果定义了一个全局对象,则在程序流程离开其作用域时,调用该全局对象的析构函数。
4.如用new运算符动态地建立了对象,当用delete运算符释放该对象时,先调用该对象的析构函数。
析构函数并不是删除对象,而是在撤销对象所占用的内存之前完成一些清理工作,而且该函数不返回任何值,没有函数类型和函数参数,一个类可以有多个构造函数,但是只能有一个析构函数。
调用构造函数和析构函数的顺序 :
调用析构函数的次序与构造函数的次序相反,最先被调用的构造函数,其对应(同一对象中)的析构函数最后被调用,即先构造的后析构,后构造的先析构。