初夏小谈:类和对象(四)(特殊的static)
一、不一样的构造函数
1.理清赋值与初始化列表
通过之前的已经知道构造函数是在创建类对象时初始化对象,那么构造函数体中的操作究竟是不是初始化呢?很明显它不是初始化,为什么这么说呢?因为在构造函数内可以进行多次赋值。而初始化只有一次,这就说明函数体内进行的是赋值操作了。
那么之前一直在说对象创建时首先调用构造函数进行初始化,那到底是怎回事呢?这当然没错,只不过初始化不在函数体,而在函数的参数列表后面进行初始化,以一个冒号开始后面跟成员变量之后的括号中放该成员的初始化值或表达式,每个成员变量之间以逗号间隔。
注意:①:每个成员变量最多可以初始化一次,这是因为对象只能初始化一次
②:如果类中包含1.const修饰的成员变量。2.引用成员变量。3.没有默认构造函数的自定义类类型变量时这三种情况必须进行初始化。编译器做不到为它们初始化。
③:成员变量初始化顺序与在构造函数参数列表后面的成员变量顺序无关,它只与成员变量在类中声明的顺序一样。
④:在创建对象时不管是否要初始化,一定尽量使用初始化变量。自定义变量一定要进行初始化
2.关于隐式类型转换
①:当用一个内置类型数据去给自定义类型对象赋值时会发生隐式类型转换。(前提:构造函数中只有一个参数)(或者其他的参数都有默认值)
②:对于这种情况会容易使我们搞混到底是值给值赋值,还是给对象赋值。结果二者都不是。对于这样的情况C++给出一个关键字explicit来防止它发生隐式类型转换。将explicit加在构造函数名前即可。
3.再谈构造函数
①.之前一直在说当没有自定义构造函数时,编译器会自动生成一个构造函数,这是在语法上的解释。但是实际上编译器不一定生成。编译器会对是否需要生成构造函数进行优化,如果编译器觉得需要就会生成。例如:成员变量如果有自定义类类型嵌套。
二、逃出三界之外的static成员
1.概念:
①:用static修饰的类成员变量叫静态成员变量,static修饰的类成员函数被称为静态成员函数,注意:静态成员变量一定要在类外进行初始化。
2.特性:
①:静态成员是所有对象共享的。不属于某个类。
②:静态成员变量需在类外定义,且不加static关键字。
③:静态成员变量可以直接用类名加静态成员名的方式访问,也可以用对象名加静态成员名的方式访问。
④:静态成员函数由于没有this指针,所以不能通过静态成员函数去访问非静态成员变量
注意:①:static修饰的类中的成员变量,类的大小将不包含被static修饰的成员变量
②:不论是通过对象是通过类来拿静态成员,还是通过类来拿,在底层都是通过类来拿(成员变量必须是共有的)
③:私有的成员函数可以调用静态成员函数(在里面调私有的静态成员变量)来达到目的。
④:静态成员函数和普通成员函数的本质区别:静态成员函数没有this指针,因此在静态成员函数中不能访问非静态成员变量和非静态成员函数。只能操作类中的静态成员变量。静态成员函数不能用const修饰。const本质修饰this指针。
⑤:静态成员函数中也不能调用非静态成员函数因为普通成员调用需要传递this指针。但在普通成员函数中可以调用静态成员函数或静态成员变量。
注意:类对象大小计算(所有非静态成员变量的大小)
this指针只能在非静态成员函数内部使用。
三、友元
友元就是在类外定义的函数或者类,想通过类外的函数或者类来访问另一个类中的成员变量,只需在该类中添加上friend+相应的函数或类的声明即可。友元可以增加类与类或者类与函数之间的耦合度。但会破坏类的封装性。慎用
1.友元函数
①:当重载输出/输入运算符时,我们需要传入两个参数即输出流对象cout和所需要输出的对象,而当把它重载成类的成员函数时就会发现this指针和输出流对象cout在和this指针抢占第一个参数位置。而我们需要cout对象占据第一个参数位置,this指针并不需要。所以只能将函数重载成全局函数,但是又想访问类中的成员变量。此时友元的出现解决这样的问题。只需将该函数的声明加在类中并且前面加上friend即可。
#include<iostream> using namespace std; class date { private: //友元函数声明 friend ostream& operator<<(ostream& _cout, const date& d); public: date(int _year,int _month,int _day) { year = _year; month = _month; day = _day; } private: int year = 2019; int month = 3; int day = 18; }; ostream& operator<<(ostream& _cout, const date& d) { _cout << d.year << " " << d.month << " " << d.day; return _cout; } int main() { date d(2019,3,19); cout << d << endl; system("pause"); return 0; }
结果显示:
注意:①:友元类可以访问类中的私有成员,但它不属于类
②:友元函数不能用const修饰
③:友元函数在声明时,可以是类中的任何地方,不受访问限定符的限制。
④:一个友元函数可以是多个类的友元函数
2友元类
友元类就是类似友元函数。将一个类在另一个类中声明为friend即可。
注意:①:友元函数或者类之间不具有交换性
②:友元函数之间也不具有传递性,就好比你是我的朋友,他是我的朋友,这不代表他是你的朋友一样。
3.友元的优点:提高了代码运行的效率
缺点:它不通过类的共有的方法就可以直接访问类的私有成员变量破坏类的封装特性
四、内部类
顾名思义内部类就是在类中定义的类。
1.特性:①:内部类不属于外部类,更不能通过外部类去访问内部类。但是可以通过内部类直接去访问外部类。
②:内部类是外部类的友元类,但外部类不是内部类的友元类。
③:内部类不受外部类访问限定符的限制,可以是三种修饰符的任何地方
④:求类大小时,只求外部类的大小,不需求内部类的大小,它就不属于外部类
珍&源码