C++(6)——类和对象
类和对象下1.再谈构造函数1.1 构造函数体赋值class Date { public: Date(int year, int month, int day) { _year year; _month month; _day day; } private: int _year; int _month; int _day; };上述构造函数在调用后对象中已经有了一个初始值但不能将其称为对对象中成员变量的初始化构造函数体中的语句只能将其称为赋初值而不能称为初始化。因为初始化只能初始化一次二构造函数体内可以多次赋值1.2 初始化列表初始化列表以一个冒号开始接着一个以逗号分隔的数据成员列表每个“成员变量”后面跟一个放在括号中的初始值或表达式对象的成员在初始化列表中定义class Date { public: Date(int year, int month, int day) : _year(year) , _month(month) , _day(day) {} private: int _year; int _month; int _day; };注意1. 每个成员变量在初始化列表中最多只能出现一次初始化只能出现一次2. 类中包含以下成员必须放在初始化列表位置进行初始化引用成员变量const成员变量自定义类型成员且该类没有默认构造函数class A { public: A(int a) :_a(a) {} private: int _a; }; class B { public: B(int a, int ref) :_aobj(a) ,_ref(ref) ,_n(10) //,_x(2) {} private: A _aobj; // 没有默认构造函数 int _ref; // 引用 const int _n; // const //int _x 1; //这里1是缺省值是给初始化列表的 };引用和const的共同特征必须在定义的时候初始化3. 尽量使用初始化列表初始化因为不管是否使用初始化列表对于自定义类型成员变量一定会先使用初始化列表初始化4.成员变量在类中的声明次序就是其在初始化列表中的初始化顺序因此 建议定义的顺序和声明的顺序保持一致class A { public: A(int a) :_a1(a) //后 1 ,_a2(_a1) //先 随机值 {} void Print() { cout_a1 _a2endl; } private: int _a2; int _a1; }; int main() { A aa(1); aa.Print(); }1.3 explicit关键字构造函数对于接收单个参数的构造函数具有类型转换的作用具体表现1. 构造函数只有一个参数2. 构造函数有多个参数除第一个参数没有默认值外其余参数都有默认值3. 全缺省构造函数class A { public: A(int a) :_a(a) { cout A(int a) endl; } private: int _a; }; int main() { A aa1(1); A aa2 2; // 隐式类型转换整形转换成自定义类型 // 2构造一个A的临时对象临时对象再拷贝构造aa2 --优化用2直接构造 //A aa3 2; //error C2440: “初始化”: 无法从“int”转换为“A ” const A aa3 2; return 0; }用explicit修饰构造函数可以禁止构造函数的隐式转换2.Static成员2.1 概念声明为static的类成员函数称为类的静态成员用static修饰的成员变量称之为静态成员变量用static修饰的成员函数称之为静态成员函数。静态成员函数一定要在类外进行初始化2.2 特性1. 静态成员为所有类对象所共享存放在静态区2. 静态成员变量必须在类外定义定义时不添加static关键字类中只是声明不能给缺省值因为缺省值时给初始化列表的3. 类静态成员可以用类名::静态成员或者对象.静态成员来访问4. 静态成员函数没有隐藏的this指针指定类域和访问限定符就可以访问不能访问任何非静态成员5. 静态成员也是类的成员受private等访问限定符的限制3.友元3.1 友元函数引入尝试去重载operator,发现没法将operator重载成成员函数。因为cout的输出流对象需要是第一个参数但是this指针默认是第一个参数二者在抢占第一个参数的位置operator同理。此时就要通过友元在类外进行重载友元函数可以直接访问类的私有成员是定义在类外部的普通函数不属于任何类但需要在类的内部声明声明时需要加friend关键字说明1. 友元函数可以访问类的私有和保护成员但不是类的成员函数2. 友元函数不能用const修饰——没有this指针3. 友元函数可以在类定义的任何地方声明不受类访问限定符限制4. 一个函数可以是多个类的友元函数5. 友元函数的调用与普通函数调用原理相同3.2 友元类友元类的所有成员函数都可以是另一个类的友元函数都可以访问另一个类中的非公有成员1. 友元关系是单向的不具有交换性2. 友元关系不能传递3. 友元关系不能继承4.内部类概念如果一个类定义在另一个类的内部这个类就叫做内部类特性1. 内部类可以定义在外部类的任何地方2. 内部类可以直接访问外部类中的static成员不需要外部类的对象/类名3. sizeof(外部类)外部类和内部类没有关系4. 内部类就是外部类的友元类参加友元类的定义5. 内部类是一个独立的类不属于外部类更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限5.匿名对象class A { public: A(int a 0) :_a(a) {cout A(int a) endl;} ~A() { cout ~A() endl;} private: int _a; }; class Solution { public: int Sum_Solution(int n) { cout Sum_Solution endl; //... return n; } }; int main() { A aa(1); // 有名对象 -- 生命周期在当前函数局部域 A(2); // 匿名对象 -- 生命周期在当前行 Solution().Sum_Solution(20); //匿名对象调用函数的方法 //A ra A(1); // 匿名对象具有常性 const A ra A(1); // const引用延长匿名对象的生命周期生命周期在当前函数局部域 return 0; }匿名函数调用函数的方法类名(参数).函数名(参数)如果没有默认构造函数有几个参数就传几个参数特性匿名对象具有常性不能被直接引用需要加const修饰const引用延长了匿名对象的生命周期与引用生命周期一致6. 拷贝对象时的一些编译器优化void Func1(A aa) {} A Func5() { A aa; return aa; } int main() { A ra1 Func5(); // 拷贝构造拷贝构造 -优化为拷贝构造 A ra2; //构造 ra2 Func5(); //构造拷贝构造赋值 A aa1; Func1(aa1); // 不会优化 Func1(A(1)); // 构造拷贝构造 -优化为构造 Func1(1); // 构造拷贝构造 -优化为构造 A aa2 1; // 构造拷贝构造 -优化为构造 return 0; }