友元
突破访问限定符限制分为友元函数和友元类,友元函数可以突破这个函数的访问限制,友元类则能够突破整个类的访问限制,类里面的所有成员无论公有私有都能被访问。使用时在函数声明或者类声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯就行。示例:
class A
{
public:
private:
void func(int a)
{/*...*/}
};
class B
{
//1.友元函数声明
// friend void func(int a);
//2.友元类声明
friend class A;
};
注意:友元类的声明是单向的,B是A的友元,但A不是B的友元。
static成员
<1>定义:用static修饰成员不属于某个类,而是存在于全局中,同时也受访问限定符限制。它的声明和定义可以分离,在类里面声明,定义在类外面(定义一定是在类外面)。static修饰的成员函数没有this指针,不能访问其他成员变量,只能访问静态成员(所以static成员函数经常和成员变量一起使用)。
<2>如何访问static成员:第一种方式就是“类名” + “ :: ” + “static成员”,第二种是先创建一个对象,用“对象” + “ . ” + “static成员”访问。
下面进行演示:
class A
{
public:
static int _a;//static成员变量声明
private:
};
int A::_a=0;//定义
int main()
{
A aa1;
cout<<aa1._a<<endl;//访问
return 0;
}
用一道习题加深理解(https://www.nowcoder.com/practice/7a0da8fc483247ff8800059e12d7caf1?tpId=13&tqId=11200&tPage=3&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
思路:创建n个对象,对象中设置两个静态成员变量,一个用来记录创建次数,一个用来记录累加结果,最后返回记录累加结果的成员变量。
内部类
就是将一个类定义在另一个类里面,但内部类不是外部类的一部分,它是独立的,和定义在全局没有区别。内部类默认为外部类的友元类(可访问外部类的所有成员),而且受外部类的访问限定符限制,如果把内部类放在外部类的private区域,则该内部类是它的专属内部类,其他地方用不了。
什么时候用:当两个类之间有紧密关联时,A类实现出来主要就是给B类使⽤,那么可以考虑把A类设计为B的内部类。就比如上面那道累加题,Sum这个类就可以定义为Solution的内部类,放在private区域(因为如果Sum被任意使用的话会破坏计数,就需要把它设为私有)。
*匿名对象
就是创建对象时不给名字。匿名对象的生命周期只有这一行,但是被引用时会延长它的生命周期直到引用被销毁时才结束。通常作为函数类类型的缺省参数使用。
编译器优化
就是编译器减少传参和传返回值的过程中可以省略的拷⻉的操作。
<1>类型转化过程中的优化:
class A
{
public:
A(int a = 0)
:_a1(a)
{}
private:
};
int main()
{
A aa1=1;//类型转换
return 0;
}
上面将整形赋给A这个类的过程:未优化时先经过构造再拷贝构造赋给A,优化就变成了直接构造,不再进行拷贝构造。
<2>传参过程中的优化:
class A
{
public:
A(int a = 0)
:_a1(a)
{}
private:
};
void f1()
{}
int main()
{
f1(1);
return 0;
}
上面将传参的过程:未优化时先构造,传值传参又调用拷贝构造传给f1,优化后就变成了直接构造。
<3>传返回值过程中的优化:
class A
{
public:
A(int a = 0)
:_a1(a)
{}
private:
};
A f2()
{
A aa;
return aa;
}
int main()
{
A aa2=f2();
return 0;
}
这里调用f2这个函数将返回值赋给aa2,原本需要构造,再拷贝构造传值返回,但经过优化,VS2019的debug版本下只用经过构造和拷贝构造(aa直接构造再拷贝构造给aa2),VS2022版本和19版的release版本下只用构造就行了,可以认为直接构造了aa2,aa相当于aa2的引用,二者地址相同。