十三 类的定义与实例化 1 类的一般形式 class/struct 类名:继承表{ 访问控制限定符: 类名(形参表):初始化表{}//构造函数 ~类名(void){}//析构函数 返回类型 函数名(形参表){}//成员函数 数据类型 变量名;//成员变量 }; 2 访问控制限定符 1)public 公有成员,类内部和外部都可以访问的成员 2)private 私有成员,只能在类的内部访问的成员 3)protected 保护成员(后面讲) 注:class定义类,默认访问控制属性是private,而struct定义的类默认的访问控制属性是public。 eg: class/struct A{ public: member1;//公有成员 private: member2;//私有成员 public: member3;//公有成员 void func(){ member1 = 200;//ok member2 = 100;//ok,类内部可以访问私有成员 } }; int main(){ A a; a.member1 //ok,类的外部可以访问公有成员 a.member2 //error,类的外部不能访问私有成员 } 3 构造函数(Constructor) class 类名{ 类名(构造形参表){ //构造函数体 } }; 1)函数名与类名相同,并且没有返回类型 2)构造函数在创建对象时自动被调用,不能像普通的成员函数一样直接去调用。 3)构造函数主要负责初始化对象,即初始化成员变量。 4 对象的创建和销毁 1)在栈区创建单个对象//重点掌握 类名 对象名(构造实参表); 类名 对象名 = 类名(构造实参表); 注:两种写法完全等价 2)在栈区创建多个对象(对象数组)//了解 类名 对象数组[元素个数] = {类名(构造实参表),类名(构造实参表)..} 3)在堆区创建/销毁单个对象//重点掌握 创建:类名* 对象指针 = new 类名(构造实参表); 销毁:delete 对象指针; 4)在堆区创建/销毁多个对象//了解 创建: 类名* 对象指针 = new 类名[元素个数]{类名(构造实参表),...}; 销毁: delete[] 对象指针; =============================== 练习:实现电子时钟类,让其构造接收当前系统时间,以秒为单位运行。 class Clock{ public: Clock(time_t t){ tm* local = localtime(&t); m_hour = local->tm_hour; m_min = local->tm_min; m_sec = lcoal->tm_sec; } void run(void){ while(1){ 计时:+1秒 打印当前时间; sleep(1); } } private: int m_hour;//小时 int m_min;//分钟 int m_sec;//秒 }; int main(){ Clock c(time(NULL)); c.run(); return 0; } ============= 5 多文件编程 1)类的声明部分放在xx.h头文件中 2)类的实现部分放在xx.cpp源程序中 3)类的使用代码一般会放在其它文件中 练习:使用多文件编程方法重构电子时钟类 ============= 十四 构造函数和初始化表 1 构造函数可以重载、可以带有缺省参数,也可以定义哑元. 2 缺省构造函数(无参构造函数) 1)如果类中没有定义任何构造函数,那么编译器会提供一个缺省(无参)构造函数。 --》对于基本类型的成员变量不做初始化 --》对类 类型的成员变量,会自动调用相应类型的无参构造函数来初始化 eg: class B{ public: B(void){ m_j = 0; } int m_j; }; class A{ public: int m_i;//基本类型的成员变量 B m_b;//类 类型的成员变量(成员子对象) }; int main(void){ A a; cout << a.m_i << endl;//不确定 cout << a.m_b.m_j << endl;//0 } 2)如果类中定义了构造函数,无论是否有参数,那么编译都不会再提供无参构造函数 3 类型转换构造函数(单参构造函数) class 目标类型{ public: [explicit] 目标类型(源类型 src){...} }; 可以实现源类型到目标类型的隐式转换 注:使用explicit关键字,可以强制这种转换必须显式的完成。 4 拷贝(复制)构造函数 1)用一个已定义的对象构造同类型的副本对象时,会调用该类的拷贝构造函数. class 类名{ 类名(const 类名& that){...} }; eg: class A{...}; A a1; A a2(a1);//拷贝构造函数 A a2 = a1;//和上面完全等价 2)如果一个类没有定义拷贝构造函数,那么编译器会为其提供一个缺省拷贝构造函数 --》对基本类型的成员变量,按字节复制 --》对类 类型成员变量,调用相应类拷贝构造函数 注:在大部分情况下,不需要自己定义拷贝构造函数,因为编译器所提供的缺省拷贝构造函数已经很好用了。 3)拷贝构造函数的调用时机 --》用已定义的对象作为类型对象的构造函数 --》以对象形式向函数传递参数 --》从函数中返回对象(有可能会被编译器优化掉)