1 引用型函数返回值
2 引用和指针
3 类型转换
1)隐士转换
2)强制转换、C++四种操作符形式类型转换
4 类和对象
======================
十三 类的定义和实例化
1 类的一般形式
class/struct 类名:继承表{
访问控制限定符:
//构造函数
类名(形参表)[:初始化表]{函数体}
//析构函数
~类名(void){函数体}
//成员函数
返回类型 函数名(形参表)[const]{//函数体}
//成员变量
数据类型 变量名;
};
2 访问控制限定符
public:公有成员,在类内部和外部都可以访问。
private:私有成员,只能在类的内部访问。
protected:保护成员(后面讲)
3 构造函数(Construtors)
class/struct 类名{
//构造函数
类名(形参表){函数体}
};
1)构造函数名字和类名相同,没有返回类型
2)构造函数在对象被创建时自动被调用
3)构造函数主要负责对象的初始化,即初始化成员变量
4)构造函数在每个对象的声明周期,一定会被自动调用,
但只会被调用一次
练习:实现电子时钟类,使用构造函数接收当前系统时间,初始化电子时钟对象,以秒运行。
class Clock{
public:
Clock(time_t t){
tm* local = localtime(&t);
//初始化成员变量:时分秒
时 = local->tm_hour;
分 = local->tm_min;
秒 = local->tm_sec;}
void run(void){
死循环{打印时间;计时+1秒;sleep(1)}}
private:
int m_hour;
int m_min;
int m_sec;
};
int main(void){
Clock c(time(NULL));
c.run();
return 0;
}
4 多文件编程:类的声明和定义可以放在不同的文件中
1)类的声明放在"xx.h"头文件中
2)类的实现部分放在"xx.cpp"源程序中
5 对象的创建和销毁
1)在栈中创建单个对象 //重点掌握
类名 对象(构造实参表);
类名 对象 = 类名(构造实参表);//和上面等价
注:如果构造函数没有参数
类名 对象;
类名 对象 = 类名();//和上面等价
2)在栈中创建对象数组
类名 对象数组[元素个数] = {类名(构造实参表),...}
3)在堆区创建/销毁单个对象 //重点掌握
创建:类名* 对象指针 = new 类名(构造实参表);
销毁:delete 对象指针;
4 在堆区创建/销毁多个对象
创建:类名* 对象指针 =
new 类名[元素个数]{类名(构造实参表),...}
销毁:delete[] 对象指针;
十四 构造函数和初始化表
1 构造函数重载
构造函数可以通过参数表的不同形成重载,创建对象时通过构造实参的类型选择匹配,表示不同对象的创建方式。
2 缺省构造函数(默认构造函数/无参构造函数)
1)如果一个类没有定义任何构造函数,编译器会提供一个缺省的无参构造函数。
2)对于类中基本类型的成员变量不初始化
3)对类 类型的成员变量(成员子对象),调用相应类的无参构造函数来初始化。
注:如果一个类定义了构造函数,无论是否有参数,那么编译器都不会再提供缺省的无参构造函数。
eg:
class A{
public:
A(void){
m_data = 0;
}
int m_data;
};
class B{
public:
int m_data;//基本类型
A m_a;//A类 类型
};
int main(void){
B b;//使用B的缺省构造函数创建b对象
cout << b.m_data << endl;//未初始化的值
//调用A的无参构造函数初始化m_a(成员子对象)
cout << b.m_a.m_data << endl;//0
}
3 类型转换构造函数(单参构造函数)
class 目标类型{
[explicit] 目标类型(源类型){...}
};
可以接收单个源类型对象实参的构造函数,支持从源类型到目标类型的隐士转换。
explicit关键字:用于修饰类型转换构造函数,强制的要求这种转换必须显示的进行。
4 拷贝构造函数(复制构造函数)
4.1 定义
用一个已存在的对象构造同类型的副本对象时,会调用该类的拷贝构造函数:
类名 (const 类名& that){...}
eg:
class A{
A(const A& that){...}
};
A a1;
A a2(a1);//调用拷贝构造函数
A a2 = a1;//和上面等价
4.2 缺省拷贝构造函数
1)如果一个类没有定义拷贝构造函数,那么编译器会为该类提供一个缺省的拷贝构造函数。
2)对基本类型的成员变量,按字节复制。
3)对类 类型的成员变量(成员子对象),调用相应类拷贝构造函数来初始化。
注:如果自己定义了拷贝构造函数,那么编译器将不再提供缺省拷贝构造函数,要实现成员变量复制的操作,必须在自己定义的拷贝构造函数中编写代码完成。
4.3 拷贝构造函数调用时机:
1)用已经定义的对象作为同类型对象构造实参
2)以对象的形式向函数传递参数
3)从函数中返回对象(有时会被编译器优化掉)
eg:
class A{
A(const A& that){...}
};
void func(A a3){...}
A func2(void){
A a4;
return a4;//3)
}
int main(void){
A a1;
A a2(a1);//1)
func(a1);//2)
A a5 = func2();//3)
}
总结:
自己定义的构造 编译器提供的构造函数
无参构造 缺省拷贝构造
拷贝构造 无
无 缺省拷贝构造、缺省无参构造
练习:构造函数的使用