杭州定制网站公司,织梦做视频网站可以吗,郴州网站制作公司,中国红河网22 内部类
22.1 内部类的概念
如果一个类定义在另一个类的内部#xff0c;这个类就叫做内部类。内部类是一个独立的类#xff0c;它不属于外部类#xff0c;更不能通过外部类的对象去访问内部类的成员#xff0c;外部类对内部类没有任何优越的访问权限#xff0c;也就是…22 内部类
22.1 内部类的概念
如果一个类定义在另一个类的内部这个类就叫做内部类。内部类是一个独立的类它不属于外部类更不能通过外部类的对象去访问内部类的成员外部类对内部类没有任何优越的访问权限也就是说它和定义在一个全局的类没有什么区别只是受外部类的类域限制。
例
#include iostream
using namespace std;
class A
{
private:int h;
public:class B{private:int b;};
};
int main()
{//B bb; //错误代码A::B bb;//B受A的类域限制return 0;
}22.2 内部类的特性
内部类天生就是外部类的友元即内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
例
#include iostream
using namespace std;
class A
{
private:static int k;int h;
public:class B // B天生就是A的友元{public:void foo(const A a){//B可以访问A的私有成员cout k endl;//OKcout a.h endl;//OK}};
};
int A::k 1;
int main()
{A::B b;b.foo(A());return 0;
}运行结果 内部类可以定义在外部类的public、protected、和private也就是任何位置。 sizeof外部类 外部类和内部类没有任何关系。
例
#include iostream
using namespace std;
class A
{
private:int h;
public:class B{private:int b;};
};
int main()
{A aa;cout sizeof(aa) endl;return 0;
}运行结果 23 匿名对象
23.1 匿名对象的引入及特性
以往我们调用成员函数的时候通常的做法是会先定义一个对象然后再通过这个对象去调用函数但是有些时候比如我们在做题目某个函数只需要被调用一次就可以了如果定义一个对象才能调用就有些麻烦了这个时候我们就可以通过匿名对象来对函数进行调用。
以往我们说不能用A aa1();这样的方式来定义对象因为编译器无法识别这是一个函数声明还是对象定义。
定义匿名对象的方式和上面的方式类似但是它不用取名字而且匿名对象的生命周期只在它出现的那一行。
例
#include iostream
using namespace std;
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) {//...return n;}
};
int main()
{A();cout ----- endl;cout Solution().Sum_Solution(10) endl;return 0;
}运行结果 从输出结果可以看到27行的时候定义了一个匿名对象到了28行后它就自动调用了析构函数。
除此之外29行还展示了匿名对象的应用场景即对于那些需要通过对象来调用函数但对象本身并不重要的情况就可以通过匿名对象进行调用。当然还有一些其他使用场景这个等以后遇到再说。
23 编译器对拷贝对象时的一些优化
在传参和传返回值的过程中为减少对象的拷贝通常编译器会对以下场景做一些优化
23.1 连续构造和拷贝构造时的优化
#include iostream
using namespace std;
class A
{
public:A(int a 0):_a(a){cout A(int a) endl;}A(const A aa):_a(aa._a){cout A(const A aa) endl;}A operator(const A aa){cout A operator(const A aa) endl;if (this ! aa){_a aa._a;}return *this;}~A(){cout ~A() endl;}
private:int _a;
};int main()
{A aa1 1;//构造拷贝构造return 0;
}运行结果 从输出结果可以看到35行代码本来应该涉及一个构造和一个拷贝构造但被编译器优化后只涉及一个构造。
23.2 参数类型为引用时的优化
#include iostream
using namespace std;
class A
{
public:A(int a 0):_a(a){cout A(int a) endl;}A(const A aa):_a(aa._a){cout A(const A aa) endl;}A operator(const A aa){cout A operator(const A aa) endl;if (this ! aa){_a aa._a;}return *this;}~A(){cout ~A() endl;}
private:int _a;
};
void Fun2(const A aa)
{}
int main()
{A aa1 1;cout ----- endl;Fun2(aa1);//aa只是aa1的别名无优化cout ----- endl;Fun2(2);//构造一个临时变量后给别名无优化cout ----- endl;Fun2(A(3));//return 0;
}运行结果 从输出结果可以看到 当函数参数类型为引用时因为形参只是实参的一个别名所以不需要做任何优化。
结论尽量使用const 传参。
23.3 传值返回时的优化
#include iostream
using namespace std;
class A
{
public:A(int a 0):_a(a){cout A(int a) endl;}A(const A aa):_a(aa._a){cout A(const A aa) endl;}A operator(const A aa){cout A operator(const A aa) endl;if (this ! aa){_a aa._a;}return *this;}~A(){cout ~A() endl;}
private:int _a;
};
void Fun1(A aa)
{}
void Fun2(const A aa)
{}
A Fun3()
{A aa;//构造return aa;//拷贝构造
}
A Fun4()
{return A();
}
int main()
{A aa1 1;cout ----- endl;Fun3();//无优化cout ----- endl;A aa2 Fun3();//本来应该是一个构造两个拷贝构造但被编译器优化为一个构造和一个拷贝构造cout ----- endl;Fun4();//构造拷贝构造-优化为直接构造A aa3 Fun4();//构造拷贝构造拷贝构造-优化为直接构造cout ----- endl;return 0;
}运行结果 从输出结果可以看到51行代码本来应该涉及一个构造和两个拷贝构造但被编译器优化为和49行代码一样只涉及一个构造和一个拷贝构造。除此之外58行代码直接返回一个匿名对象时本来应该涉及一个构造和两个拷贝构造但被编译器优化后只涉及一个构造。
需要注意的是下面这种情况无法优化
A aa1;
aa1 Fun4();原因在于和A aa3 Fun4();相比aa1 Fun4();还涉及到赋值运算符的重载这将干扰优化的进行。
结论
接收返回值对象尽量以拷贝构造的方式接收不要赋值接收。函数中返回对象时尽量返回匿名对象。