第三站:类与对象(下)

发布时间:2026/6/30 2:11:27

第三站:类与对象(下) const修饰成员函数有const修饰的函数不能调用没有const修饰的函数没有const修饰的函数可以调用有const修饰的函数。#includeiostreamusing namespace std;//创建类classDate{public://构造函数Date(intyear0,intmonth1,intday1){_yearyear;_monthmonth;_dayday;}//拷贝构造Date(constDated){_yeard._year;_monthd._month;_dayd._day;}////打印//void Print() {// cout _year - _month - _day endl;//}// //编译器编译为/*void Print(Date* this ) { cout this-_year - this- _month - this-_day endl; }*///打印,在函数后面加上const修饰voidPrint()const{cout_year-_month-_dayendl;}//编译器编译为/*void Print(const Date* this ) { cout this-_year - this- _month - this-_day endl; }*/private:int_year;int_month;int_day;};//void fun(Date d) {// d.Print();//}//若在参数内加const修饰d就不能调用Print函数// 因为它传入的参数是非const修饰的我们要在Print函数后加上const修饰后才能继续调用voidfun(constDated){d.Print();//编译器编译为d.Print(d);}intmain(){Dated1(2026,4,22);fun(d1);return0;}注意#情况1constDate*p1-const修饰*p1指向对象不能改但*p1可以改 #情况2Dateconst*p2-const修饰*p2指向对象不能改但*p2可以改 情况1和情况2类似Date*constp3-const修饰p3指向指针本身不能改但*p3可以改 小结 看const离谁近谁就不能改const在*左边锁住内容内容不能改变const在*右边锁住指针本身对象不能修改类中成员变量的初始化类中的构造函数体中的语句不能称为初始化因为初始化只能初始化一次而构造函数体内可以赋值多次所以只能称其为赋初值。怎样对类中成员变量的初始化以一个冒号开始接着是一个以逗号分隔的数据成员列表每个成员变量后面跟一个放在括号中的初始值或表达式。如下代码classTime{public://初始化Time(inthour,intsecond,intminute):_hours(hour)//初始化每个成员变量只在初始化列表中初始化一次,_seconds(second),_minutes(minute){}private:int_hours;int_seconds;int_minutes;};注意必须在初始化列表初始化的成员变量1.引用成员变量2.const成员变量3.自定义类型成员变量classA{public:A(inta):_a(a){}private:int_a;};classB{public://初始化成员变量B(inta,intf1):_a1(a),f(f1)//对引用初始化等价于》int f f1;,n(10){}private:A_a1;//声明没有默认构造函数intf;//引用,只是声明不是定义constintn;//const修饰};警告小贴士成员变量在类中声明次序就是其在初始化列表中的初始化顺序与其在初始化列表中的先后次序无关如图先初始化_b1,因为此时_b2是随机值所以_b1被初始化为随机值了_b2被初始化为10。explicit关键字的使用构造函数不仅可以构造与初始化对象对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数还具有类型转换的作用。使用explicit关键字可以禁止类型转换。//explicit关键字的使用classDate{public://无explicit修饰具有类型转换的作用// explicit修饰构造函数禁止类型转换Date(intyear0,intmonth1,intday1)//去掉explicit修饰之后代码可以通过编译:_year(year),_month(month),_day(day){coutDate(int year 0, int month 1, int day 1)endl;}/* // 多个参数但是创建对象时后两个参数可以不传递没有使用explicit修饰具有类型转换作用 // explicit修饰构造函数禁止类型转换 explicit Date(int year, int month 1, int day 1) : _year(year) , _month(month) , _day(day) {} *///拷贝构造//拷贝构造Date(constDated){_yeard._year;_monthd._month;_dayd._day;coutDate(const Date d)endl;}Dateoperator(constDated){if(this!d){_yeard._year;_monthd._month;_dayd._day;}coutDate operator(const Date d)endl;return*this;}voidPrint(){cout_yearendl;}private:int_year;int_month;int_day;};voidTest(){Dated1(2022);d12023;//隐式类型转换加上explicit后就编译错误。先用2023构造出零时对象tmp//【再用 tmp 赋值给 d1调用 d1.operator(tmp)本例中会自动生成赋值的默认函数不用写也会自动生成】其他类型的会进行拷贝构造d1.Print();}intmain(){Test();return0;}C11支持的写法构造函数传参#includeiostreamusing namespace std;classDate{public://构造函数Date(intyear0,intmonth1,intday1):_year(year),_month(month),_day(day){coutDate(int year 0, int month 1, int day 1)endl;cout_year-_month-_dayendl;}//拷贝构造Date(constDated){_yeard._year;_monthd._month;_dayd._day;coutDate(const Date d)endl;}Dateoperator(constDated){if(this!d){_yeard._year;_monthd._month;_dayd._day;}coutDate operator(const Date d)endl;return*this;}private:int_year;int_month;int_day;};intmain(){Dated1(2026,4,23);d1{1,2,3};//先调用构造函数构造出tmp(1,2,3)临时变量再调用赋值运算符重载把tmp赋值给d1.因为//d1 已经是一个完整的 Date 对象了C 不允许你直接把{ 1,2,3 } 塞给 d1//编译器只能先用{ 1,2,3 } 造出一个临时的 Date 对象tmp再把这个临时对象赋值给 d1。Dated2{4,5,6};//c11才支持只调用了构造函数为什么不是把某种类型转成 Date而是直接用参数列表构造 Date所以不是隐式类型转换Dated31;//传入一个参数表示年Dated4{1,2};//传入两个参数时表示年和月return0;}在成员变量声明时赋初始值//#includeiostream//using namespace std;//class Date {//public:// void Print() {// cout _year - _month - _day endl;// }//private:// int _year;// int _month;// int _day;//};//int main() {// Date d1;// d1.Print();//输出随机值// return 0;//}#includeiostreamusing namespace std;classDate{public:voidPrint(){cout_year-_month-_dayendl;}private://C11int_year0;int_month1;int_day1;};intmain(){Dated1;d1.Print();//0-1-1return0;}static关键字特点静态成员为所有类对象所共享不属于某个具体的对象存放在静态区静态成员变量必须在类外定义定义时不添加static关键字类中只是声明类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问静态成员函数没有隐藏的this指针(this指针存储对象的地址)不能访问任何非静态成员静态成员也是类的成员受public、protected、private 访问限定符的限制#includeiostreamusing namespace std;classA{public:A(){n;}A(constAa){n;}staticintGetN(){//cout n endl;编译错误为什么静态函数没有this指针//因为static修饰的函数叫静态成员函数函数属于类不属于任何对象调用所以不需要this指针// 注意所有函数都在代码段静态普通函数returnn;}private:staticintn;//声明};//定义intA::n0;Af1(Aa){returna;}intmain(){Aa1;Aa2;f1(a1);f1(a2);coutA::GetN()endl;return0;}友元友元是一种突破封装的方式因此会增加耦合度破坏了封装。但有时仍然可以提供便利。普通函数调用类里面的私有成员以如下方式类外函数不能调用类中的私有限制的成员变量#includeiostreamusing namespace std;classDate{public:Date(intyear0,intmonth1,intday1){_yearyear;_monthmonth;_dayday;}voidPrint(){cout_year-_month-_dayendl;}private:int_year0;int_month1;int_day1;};voidf(Dated){//d._year 10;编译报错不能调用类里面的成员变量//cout d._year endl;//编译报错}intmain(){Dated1;d1.Print();f(d1);return0;}友元函数特征友元函数可访问类的私有和保护成员友元函数不能用const修饰友元函数可以在类定义的任何地方声明不受类访问限定符限制一个函数可以是多个类的友元函数友元函数的调用与普通函数的调用原理相同在类中声明类外的函数为友元函数函数就可以调用类里面的私有成员//在类中声明类外的函数为友元函数函数就可以调用类里面的私有成员#includeiostreamusing namespace std;classDate{friendvoidf(Dated);//声明了f(Date d)为友元函数public:Date(intyear0,intmonth1,intday1){_yearyear;_monthmonth;_dayday;}voidPrint(){cout_year-_month-_dayendl;}private:int_year0;int_month1;int_day1;};voidf(Dated){d._year10;//可以调用类里面的成员变量coutd._yearendl;}intmain(){Dated1;d1.Print();f(d1);return0;}友元函数的使用重载cout和cin函数在类中重载在类中重载operatord1 cout; 等价于》 d1.operator(d1, cout); 不符合常规调用因为成员函数第一个参数一定是隐藏的this所以d1必须放在的左侧区调用类中的函数可读性不高所以我们可以写在类外让该函数成为类中的友元函数#includeiostreamusing namespace std;//重载operator函数classDate{public://构造函数Date(intyear0,intmonth1,intday1){_yearyear;_monthmonth;_dayday;}voidPrint(){cout_year-_month-_dayendl;}//在类中重载operator// d1 cout; - d1.operator(d1, cout); 不符合常规调用// 因为成员函数第一个参数一定是隐藏的this所以d1必须放在的左侧区调用类中的函数// 可读性不高所以我们可以写在类外让该函数成为类中的友元函数ostreamoperator(ostreamout){out_year-_month-_dayendl;returnout;}private:int_year;int_month;int_day;};intmain(){Dated1(2026,4,24);d1cout;d1.operator(cout);return0;}在类外重载使其变为友元函数可以调用类中的私有成员变量1.重载cout函数//在类外重载使其变为友元函数可以调用类中的私有成员变量#includeiostreamusing namespace std;//重载operator函数classDate{friend ostreamoperator(ostreamout,constDated);public://构造函数Date(intyear0,intmonth1,intday1){_yearyear;_monthmonth;_dayday;}voidPrint(){cout_year-_month-_dayendl;}private:int_year;int_month;int_day;};ostreamoperator(ostreamout,constDated){outd._year-d._month-d._dayendl;returnout;}intmain(){Dated1(2026,4,24);coutd1;return0;}2.重载cin函数//在类外重载使其变为友元函数可以调用类中的私有成员变量#includeiostreamusing namespace std;//重载operator函数classDate{friend istreamoperator(istreamin,Dated);public://构造函数Date(intyear0,intmonth1,intday1){_yearyear;_monthmonth;_dayday;}voidPrint(){cout_year-_month-_dayendl;}private:int_year;int_month;int_day;};istreamoperator(istreamin,Dated){ind._year;ind._month;ind._day;returnin;}intmain(){Dated1;cind1;d1.Print();return0;}友元类友元类表示一个类是另一个类的友元类友元类的所有成员函数都可以是另一个类的友元函数都可以访问另一个类中的非公有成员。特点友元关系是单向的不具有交换性。比如下面A类和B类在A类中声明B类为其友元类那么可以在B类中直接访问A类的私有成员变量但想在A类中访问B类中私有的成员变量则不行。友元关系不能传递如果C是B的友元 B是A的友元则不能说明C时A的友元。

相关新闻