day_04_类的定义和实例化、构造函数和初始化表

时间:2021-08-09 19:26:20

十三、类的定义和实例化

1、类的语法形式

struct/class 类名:继承表{
访问控制限定符:
类名(形参表):初始化表{} //构造函数
~类名(void){} //析构函数
返回类型 函数名(形参表)[const]{} //成员函数
数据类型 变量名; //成员变量
}

2、访问控制限定符

public:公有成员,在类的外部和内部都可以访问的成员;
private:私有成员,只能在类的内部访问的成员;
protected:保护成员(后面讲)

eg:

struct/class {
eee; //struct默认公有成员,class默认私有成员
public:
aaa; //公有成员
private:
bbb; //私有成员
public:
ccc;
ddd;
};

3、构造函数(Constructor)

class 类名{
类名(形参表){} //构造函数
}

 1)函数名和类名相同,没有返回类型;
 2)构造函数在对象被创建时自动被调用;
 3)构造函数主要负责初始化对象,即初始化成员变量;

4、对象的创建和销毁

 1)在栈区创建单个对象
   类名 对象(构造实参表);
   类名 对象 = 类名(构造实参表);

注意:
   如果构造函数没有参数,类名 对象;类名 对象 = 类名();

 2)在栈区创建对象数组
   类名 对象数组[元素个数] = {类名(构造实参表), … };
 3)在堆区创建单个对象
 创建:
   类名* 对象指针 = new 类名(构造实参表);
 销毁:
   delete 对象指针
 4)在堆区创建对象数组
 创建:
   类名* 对象指针 = new 类名[元素个数]{类名(构造实参表), ...}
 销毁:
   delete[] 对象指针;

练习:实现一个电子时钟,用构造函数接收当前系统时间,可以以秒为单位运行;

class Clock{
public:
Clock(time_t t){ //time_t = long int;
tm* local = localtime(&t);
m_hour = local->tm_hour;
...
}
void run(void){
while(1){
//打印当前时间
printf("\r%02d:%02d:%02d", m_hour, m_min, m_sec);
// 刷新标准输出缓冲区
fflush(stdout);
//计时加1
//sleep(1)
}
}
private:
int m_hour;
int m_min;
int m_sec;
};
int main(void)
{
//time(NULL):获取当前系统的时间
Clock clock(time(NULL));
clock.run();
}

5、多文件编程

 1)类的声明部分放在xx.h文件中;
 2)类的实现部分放在xx.cpp源文件中;
 3)使用该类的代码一般会在其它的文件中;

练习:将Clock类拆分成多文件形式;


十四、构造函数和初始化表

1、构造函数可以重载也可以带有缺省参数

2、缺省构造函数

如果一个类没有定义任何构造函数,编译器会提供一个缺省构造函数(无参构造函数);

 1)对于基本类型成员不做初始化;
 2)对于类 类型成员变量,会自动调用相应类的无参构造函数来初始化;

注意:
  如果定义了构造函数,无论是否有参数,编译器都不会提供缺省构造函数了;

3、类型转换构造函数(单参构造函数)

class 目标类型{
目标类型(源类型 src){...}
};
// 可以实现源类型到目标类型的隐式转换

注意:
  使用explicit关键字修饰该构造函数,可以强制这种通过构造函数实现的类型转换必须显示的完成。

4、拷贝构造函数(重难点)

 1)用一个已经存在的对象构造同类型的副本对象,会调用拷贝构造函数;
语法:
   类名(const 类型& that){//完成成员的拷贝}
eg:

class A{
public:
A(const A& that){...}
};
A a1; // 无参方式构造a1
A a2(a1); // 调用拷贝构造函数来构造a2
A a2 = a1; // 和上面等价