专业做网站方案ppt,什么是网络营销?网络营销的内容有哪些?你是怎么理解的?,做网站servlet,建设网站申请空间需要多少钱#x1f308;个人主页#xff1a;秋风起#xff0c;再归来~#x1f525;系列专栏#xff1a;C从入门到起飞 #x1f516;克心守己#xff0c;律己则安
目录
1、友元
2、内部类
3、 匿名对象
4、对象拷⻉时的编译器优化
5、完结散花 1、友元
• 友元提供… 个人主页秋风起再归来~系列专栏C从入门到起飞 克心守己律己则安
目录
1、友元
2、内部类
3、 匿名对象
4、对象拷⻉时的编译器优化
5、完结散花 1、友元
• 友元提供了⼀种突破类访问限定符封装的⽅式友元分为友元函数和友元类在函数声明或者类 声明的前⾯加friend并且把友元声明放到⼀个类的⾥⾯。
友元类
class A
{
public://B是A的友元类friend class B;
private:int _a1 1;int _a2 2;
};class B
{
public:B(){//......}void func(const A aa){//访问A的私有成员cout aa._a1 endl;cout aa._a2 endl;}
private:int _b1 3;int _b2 4;
};int main()
{A aa1;B bb1;bb1.func(aa1);return 0;
} 友元函数
class A
{
public://B是A的友元类(友元声明)friend class B;//func是A类的友元函数(友元声明)friend void func(const A aa);
private:int _a1 1;int _a2 2;
};void func(const A aa)
{cout aa._a1 endl;cout aa._a2 endl;
} • 外部友元函数可访问类的私有和保护成员友元函数仅仅是⼀种声明他不是类的成员函数。
• 友元函数可以在类定义的任何地⽅声明不受类访问限定符限制。
• ⼀个函数可以是多个类的友元函数。
// 前置声明不然A的友元函数声明编译器不认识B
class B;class A
{
public://B是A的友元类(友元声明)friend class B;//func是A类的友元函数(友元声明)friend void func(const A aa,const B bb);
private:int _a1 1;int _a2 2;
};class B
{
public:friend void func(const A aa, const B bb);
private:int _b1 3;int _b2 4;
};void func(const A aa, const B bb)
{cout aa._a1 endl;cout aa._a2 endl;cout bb._b1 endl;cout bb._b2 endl;
}int main()
{A aa1;B bb1;func(aa1,bb1);return 0;
} • 友元类中的成员函数都可以是另⼀个类的友元函数都可以访问另⼀个类中的私有和保护成员。 • 友元类的关系是单向的不具有交换性⽐如A类是B类的友元A可以访问B的私有或保护成员但B不可以但是B类不是A类的友元。
• 友元类关系不能传递如果A是B的友元B是C的友元但是A不是B的友元。
• 有时提供了便利。但是友元会增加耦合度破坏了封装所以友元不宜多⽤。
2、内部类
• 如果⼀个类定义在另⼀个类的内部这个内部类就叫做内部类。内部类是⼀个独⽴的类跟定义在 全局相⽐他只是受外部类类域限制和访问限定符限制所以外部类定义的对象中不包含内部类。
• 内部类默认是外部类的友元类即内部类可以访问外部类的私有和保护成员。 class A
{
public://内部类class B//默认是A的友元类{public:void func(A aa){A::a;aa.b;//访问A类的私有成员}private:int b1 1;int b2 2;};
private:static int a;int b 1;
};int main()
{A a;cout sizeof(a) endl;return 0;
}
a对象的大小是4说明B类是一个独立的类 外部类定义的对象中不包含内部类 • 内部类本质也是⼀种封装当A类跟B类紧密关联A类实现出来主要就是给B类使⽤那么可以考 虑把A类设计为B的内部类如果放到private/protected位置那么A类就是B类的专属内部类其 他地⽅都⽤不了。
上篇文章的OJ题就可以用内部类来进行封装
求123...n_⽜客题霸_⽜客⽹ 描述 求123...n要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句A?B:C。 数据范围0n≤200 进阶 空间复杂度 O(1) 时间复杂度 O(n) 示例1 输入 5 复制返回值 15示例2 输入 1 复制返回值 1OJ链接 class Solution
{class Sum{public:Sum(){reti;i;}};static int i;static int ret;
public:int Sum_Solution(int n){//Sum a[n];变长数组//创建n个对象来调用n次构造函数Sum* pnew Sum[n];return ret;}};
//用静态的成员变量来记录结果
int Solution::i1;
int Solution::ret0;
3、 匿名对象
• ⽤类型(实参)定义出来的对象叫做匿名对象相⽐之前我们定义的类型对象名(实参)定义出来的 叫有名对象
• 匿名对象⽣命周期只在当前⼀⾏⼀般临时定义⼀个对象当前⽤⼀下即可就可以定义匿名对象。
class A
{};int main()
{A();//定义的匿名对象生命周期只存在当前这一行
}
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 aa1;// 不能这么定义对象因为编译器⽆法识别下⾯是⼀个函数声明还是对象定义//A aa1();// 但是我们可以这么定义匿名对象匿名对象的特点不⽤取名字// 但是他的⽣命周期只有这⼀⾏我们可以看到下⼀⾏他就会⾃动调⽤析构函数A();A(1);A aa2(2);// 匿名对象在这样场景下就很好⽤当然还有⼀些其他使⽤场景这个我们以后遇到了再说Solution().Sum_Solution(10);return 0;
}4、对象拷⻉时的编译器优化
• 现代编译器会为了尽可能提⾼程序的效率在不影响正确性的情况下会尽可能减少⼀些传参和传参 过程中可以省略的拷⻉。
• 如何优化C标准并没有严格规定各个编译器会根据情况⾃⾏处理。当前主流的相对新⼀点的编 译器对于连续⼀个表达式步骤中的连续拷⻉会进⾏合并优化有些更新更激进的编译还会进⾏跨 ⾏跨表达式的合并优化。
class A
{
public:A(int a0){cout 调用构造 endl;}A(const A a){cout 调用拷贝构造 endl;}~A(){cout 调用析构 endl;}
private:int _a;
};int main()
{//原来是先用1调用构造创建一个临时对象再用临时对象拷贝构造对象a1//在VS2022上编译器优化为直接构造a1A a1 1;return 0;
} 原来是先用1调用构造创建一个临时对象再用临时对象拷贝构造对象a1在VS2022上编译器优化为直接构造a1
跨 ⾏跨表达式的没有优化
class A
{
public:A(int a0){cout 调用构造 endl;}A(const A a){cout 调用拷贝构造 endl;}~A(){cout 调用析构 endl;}
private:int _a;
};void f(A aa)
{//......
}int main()
{A a(1);//构造f(a);//传值传参拷贝构造return 0;
} 构造与拷贝构造并没有在一个连续的步骤当中所以编译器并没有进行优化!
匿名对象触发优化隐式类型转换触发优化
int main()
{//A a(1);//构造//f(a);//传值传参拷贝构造f(A(1));//匿名对象触发优化cout endl;f(1);//隐式类型转换触发优化return 0;
} 传值返回进行优化
class A
{
public:A(int a0){_a a;cout 调用构造 endl;}A(const A a){cout 调用拷贝构造 endl;}~A(){cout 调用析构 endl;}void Print(){cout _a- _a endl;}
private:int _a;
};void f(A aa)
{//......
}//传值返回
A f2()
{A aa(1);//调用构造return aa;//调用拷贝构造创建临时对象
}int main()
{f2().Print();return 0;
}
在VS2019debug模式下f2函数体内先调用构造函数初始化aa, 再用aa调用拷贝构造创建临时对象作为返回值函数调用结束后aa生命周期结束调用析构函数。临时对象作为返回值其生命周期在当前一行调用Print函数后生命周期结束再次调用析构。 而在在VS2022debug模式下其优化更为激进编译器并没有构造aa而是直接构造临时对象。为什么是没有构造aa呢原因就在于析构函数的调用是在Print函数调用之后才调用的 既然编译器敢这么优化就不怕出bug吗下面我们来写一个程序测试一下
class A
{
public:A(int a0){_a a;cout 调用构造 endl;}A(const A a){cout 调用拷贝构造 endl;}~A(){cout 调用析构 endl;}void Print(){cout _a- _a endl;}//这里重载一个前置A operator(){_a 100;return *this;}
private:int _a;
};void f(A aa)
{//......
}//传值返回
A f2()
{A aa(1);//调用构造aa;//如果编译器还像之前那样优化并且打印的_a是101就算他牛逼return aa;//调用拷贝构造创建临时对象
}int main()
{f2().Print();return 0;
} 这里没有构造aa,却在构造临时对象时根据程序员的想法对_a进行了操作我们可以看到编译器敢这么优化他还是敢作敢当的
5、完结散花
好了这期的分享到这里就结束了~
如果这篇博客对你有帮助的话可以用你们的小手指点一个免费的赞并收藏起来哟~
如果期待博主下期内容的话可以点点关注避免找不到我了呢~
我们下期不见不散~~