当前位置: 首页 > news >正文

茶叶网页设计图片/seo网站有优化培训吗

茶叶网页设计图片,seo网站有优化培训吗,中国新兴建设招聘网站,wordpress前台多语言版文章目录 前言一. 再探构造函数初始化列表特性总结练习 二. 类型转换2.1 隐式类型转换2.2 临时对象具有常性2.3 explicit关键字2.4 多参数类型转化 三. static成员概念特性练习 四. 友元概念特性 五. 内部类概念特性 六. 匿名对象概念特性 七. 对象拷贝时的编译器优化END 前言 …

文章目录

  • 前言
  • 一. 再探构造函数
    • 初始化列表
    • 特性
    • 总结
    • 练习
  • 二. 类型转换
    • 2.1 隐式类型转换
    • 2.2 临时对象具有常性
    • 2.3 explicit关键字
    • 2.4 多参数类型转化
  • 三. static成员
    • 概念
    • 特性
    • 练习
  • 四. 友元
    • 概念
    • 特性
  • 五. 内部类
    • 概念
    • 特性
  • 六. 匿名对象
    • 概念
    • 特性
  • 七. 对象拷贝时的编译器优化
  • END


前言

在学习C++类和对象上和中的基础上,我们继续来学习C++类和对象剩下的内容,大致包括构造函数的初始化列表,隐式类型转换,static成员,友元,内部类,匿名对象,对象拷贝时编译器的优化。

一. 再探构造函数

初始化列表

之前我们实现构造函数时,初始化成员变量主要使用函数体内赋值,构造函数初始化还有一种方式,就是初始化列表

初始化列表的使用方式是以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。而函数体可以实现其它功能。

class Date
{
public:Date(int year, int month, int day):_year(year),_month(month),_day(day){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};

对于自定义类型的成员,编译器自动调用它的默认构造函数,初始化列表可以不显示写。但是当这个自定义类型的成员没有默认的构造函数时,我们需要在初始化列表显示调用它的构造函数,否则就会报错。

#include<iostream>
using namespace std;
class Time
{
public:Time(int hour):_hour(hour){cout << "Time()" << endl;}
private:int _hour;
};
class Date
{
public:Date(int year = 1, int month = 1, int day = 1):_year(year),_month(month),_day(day),_t(10){}void Print() const{cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;Time _t; //没有默认构造函数
};
int main()
{Date d1;d1.Print();return 0;
}

可以看到类Time没有默认构造函数,所以我们需要手动在初始化列表里调用类对象_t的构造函数来实现初始化。如果不写就会报错,如下:

在这里插入图片描述

特性

1.每个成员变量在初始化列表中只能出现一次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。

当有成员变量在初始化列表出现两次就会报错,如下:
在这里插入图片描述

2.引用成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进行初始化,否则会编译报错。

#include<iostream>
using namespace std;
class Time
{
public:Time(int hour):_hour(hour){cout << "Time()" << endl;}
private:int _hour;
};
class Date
{
public:Date(int& x, int year = 1, int month = 1, int day = 1):_year(year),_month(month),_day(day),_t(10),_i(x),j(1){}void Print() const{cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;Time _t; //没有默认构造的类类型变量int& _i; //引用类型变量const int j; //const成员变量
};
int main()
{int i = 0;Date d1(i);d1.Print();return 0;
}

如果不放在初始化列表进行初始化,就会发生如下报错:
在这里插入图片描述
3.C++11支持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显示在初始化列表初始化的成员使用的。

#include<iostream>
using namespace std;
class Time
{
public:Time(int hour):_hour(hour){cout << "Time()" << endl;}
private:int _hour;
};
class Date
{
public:Date(int& x):_i(x){}void Print() const{cout << _year << "/" << _month << "/" << _day << endl;}
private:// 注意这里不是初始化,这里给的是缺省值,这个缺省值是给初始化列表的// 如果初始化列表没有显示初始化,默认就会用这个缺省值初始化int _year = 2024;int _month = 11;int _day = 4;Time _t = 10;int& _i;const int j = 1;
};
int main()
{int i = 0;Date d1(i);d1.Print();return 0;
}

在这里插入图片描述
通过调试可以看出:当在成员变量声明时给缺省值,这个缺省值会给到初始化列表,如果没有在初始化列表里初始化成员变量,编译器会自动调用缺省值去初始化成员变量

  1. 尽量使用初始化列表初始化,因为那些不在初始化列表初始化的成员也会走初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会用这个缺省值初始化。如果没有给缺省值,对于没有显示在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有显示在初始化列表初始化的自定义类型成员会调用这个成员的默认构造函数,如果没有默认构造会编译错误。

在这里插入图片描述
5.初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的的先后顺序无关建议声明顺序和初始化列表顺序保持一致

#include<iostream>
using namespace std;
class Time
{
public:Time(int hour):_hour(hour){cout << "Time()" << endl;}
private:int _hour;
};
class Date
{
public:Date(int& x):_i(x),_t(10),_month(11),_year(2024),_day(4){}void Print() const{cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;Time _t;int& _i;
};
int main()
{int i = 0;Date d1(i);d1.Print();return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

进入调试可以知道,编译器不是按照成员在初始化列表出现的顺序来对成员进行初始化的,而是按照成员在类中声明的顺序

总结

无论是否显示写初始化列表,每个构造函数都有初始化列表
无论是否在初始化列表显示初始化,每个成员变量都要走初始化列表初始化

练习

#include<iostream>
using namespace std;
class A
{
public:A(int a):_a1(a), _a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}
private:int _a2 = 2;int _a1 = 2;
};
int main()
{A aa(1);aa.Print();return 0;
}

这段程序的运行结果是什么呢?我们先来看结果

在这里插入图片描述
这里有以下需要注意的地方:

1.成员变量在声明时给的值是缺省值,这个缺省值是给初始化列表的,不是初始化成员的。如果成员变量在初始化列表里显示初始化了,这个缺省值就不需要了,否则就用这个缺省值来对成员变量进行初始化。
2.初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的的先后顺序无关

因为_a1和_a2都是int类型(内置类型),所以编译器一开始不做处理,_a1和_a2都是随机值。类A的初始化列表先初始化_a2,_a2初始化为_a1,所以_a2还是随机值,然后再初始化_a1,_a1初始化为形参a,所以_a1初始化为1。

二. 类型转换

2.1 隐式类型转换

C++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。隐式类型转换(也称为类型强制转换)涉及将一种类型的对象转换为另一个类型的对象,而不需要显示地使用类型转换运算符。这种转换通常通过类的单参数构造函数来实现,这种构造函数被称为转换构造函数。

例如:

class MyClass {  
public:  MyClass(int value) {  // 转换构造函数  // 用于将 int 类型转换为 MyClass 类型  }  
};
#include<iostream>
using namespace std;
class A
{
public:A(int a):_a(a){cout << "A(int a)" << endl;}A(const A& aa){_a = aa._a;_b = aa._b;cout << "A(const A& aa)" << endl;}void Print() {cout << _a << " " << _b << endl;}
private:int _a;int _b = 1;
};
int main()
{// 1构造⼀个A的临时对象,再用这个临时对象拷贝构造aa// 编译器遇到连续构造+拷贝构造->优化为直接构造A aa = 1;aa.Print();return 0;
}

A aa = 1 这种将整数类型赋值给自定义类型有着明显的逻辑错误,但是类A实现了单个(整数)参数的构造函数,所以编译器调用类A的转换构造函数 A(int a) 来创建一个 A 类型的临时对象,这个临时对象是通过调用 A(1) 来构造的。最后通过调用 aa 的拷贝构造函数来实现 aa 对临时对象的拷贝。

在这里插入图片描述

注意:在C++11及以后的版本中,C++编译器可能会应用返回值优化命名返回值优化来避免不必要的临时对象创建和拷贝。这样就不会调用拷贝构造函数,编译器可以直接在目标对象的内存位置构造对象,而不是先创建一个临时对象再进行拷贝。

当编译器进行优化为直接构造时,对于创建对象aa的过程如下:

1.识别到A aa = 1;这一语句需要将整数 1 转换为A类型对象。
2.编译器直接在aa对象的内存位置调用构造函数A(int a),将参数 1 传入该构造函数。
3.构造函数内部,将参数 1 赋值给成员变量_a,并根据默认初始化规则初始化成员变量_b(如果没有显式指定初始值,_b会按照其类型进行默认初始化)。
4.这样就完成了对aa对象的构造,整个过程没有临时对象的创建和调用拷贝构造函数。

注意如果编译器进行优化为直接构造,通常相当于没有临时对象创建,但整数 1 仍然会隐式转换为 A 类型对象

因为即使是直接在目标对象的内存位置构造对象,编译器在识别到需要将整数转换为 A 类型对象时,仍然会调用接受一个整数参数的构造函数 A(int a)来进行类型转换操作。这个过程本质上还是隐式类型转换,只是编译器可能避免了创建临时对象和调用拷贝构造函数的额外开销。

2.2 临时对象具有常性

在这里插入图片描述

在上述例子中,如果尝试用A类型对象对整数1进行引用,编译器会报错。因为当整数1隐式类型转换为A类型的临时对象后,该临时对象具有常性,如果用非常量引用去引用该临时对象会导致权限的放大,从而导致编译器报错。

当使用const修饰引用时(const引用),编译器就不会报错。

#include<iostream>
using namespace std;
class A
{
public:A(int a):_a(a){}//因为打印函数不用改变对象的成员变量,所以这里最好使用const修饰this指针指向的对象//这样就防止通过this指针去修改对象的成员//也防止了常量对象调用Print函数时造成权限放大而导致编译器报错void Print() const{cout << _a << " " << _b << endl;}
private:int _a;int _b = 1;
};
int main()
{const A& aa = 1;aa.Print();return 0;
}

内置类型的类型转换

当内置类型发生类型转换时也会生成临时对象,引用该临时对象必须使用const引用,const 引用绑定到临时对象后会延长该临时对象的生命周期。

#include<iostream>
using namespace std;
int main()
{int i = 1;double d = i;// 不报错,整数i隐式类型转换为double类型,再赋值给d//double& d1 = i;// 报错,i创建了一个double类型的临时对象,临时对象具有常性,导致权限放大,编译器报错const double& d2 = i;// 不报错,权限的平移return 0;
}

类类型的类型转换

类类型的对象之间也可以隐式转换,需要相应的构造函数支持。比如整数1转换为类类型对象需要单参数(整数)的构造函数,同理,类类型对象之间的相互转换(A类型转换为B类型)也需要单参数(A类型对象)的构造函数。

#include<iostream>
using namespace std;
class A
{
public:A(int a1):_a1(a1){}void Print(){cout << _a1 << " " << _a2 << endl;}int Get() const{return _a1 + _a2;}
private:int _a1 = 1;int _a2 = 2;
};
class B
{
public://使用const引用减少拷贝,同时不会修改源对象的成员B(const A& a):_b(a.Get()){}
private:int _b = 0;
};
int main()
{A aa = 1;A aa1 = 2;// aa隐式类型转换为b对象// 原理跟上面类似B b = aa;const B& rb = aa1;// aa1创建了一个B类型的临时对象,因为临时对象具有常性,所以要使用const引用return 0;
}

2.3 explicit关键字

构造函数前面加explicit就不再支持隐式类型转换。

explicit A(int a):_a1(a), _a2(_a1)
{}

在这里插入图片描述
当整数1转换为A类型对象时会调用构造函数A(1),但是构造函数前面加了explicit关键字,使得整数1不能隐式地进行类型转换。

2.4 多参数类型转化

多参数的类型转换需要有相对应的多参数构造函数才能实现。C++11之后才支持多参数转化。

多参数的类型转换需要使用花括号 { }

#include<iostream>
using namespace std;
class A
{
public:A(int a1):_a1(a1){}A(int a1, int a2):_a1(a1), _a2(a2){}void Print(){cout << _a1 << " " << _a2 << endl;}int Get() const{return _a1 + _a2;}
private:int _a1 = 1;int _a2 = 2;
};
int main()
{// C++11之后才支持多参数转化A aa3 = { 2,2 };return 0;
}

同样地,若多参数构造函数不期望支持隐式类型转换,只需在构造函数前面加上explicit关键字即可

三. static成员

概念

static 成员,即静态成员,是编程中面向对象编程语言中的一个概念,它属于类而不是类的某个特定实例(对象)。

特性

  • 用static修饰的成员变量,称之为静态成员变量,静态成员变量一定要在类外进行初始化
#include<iostream>
using namespace std;
class A {
public://静态成员不能在类里面初始化/*A(int i = 1):_a(i){}*/void Print() const{cout << _a << endl;}
private:static int _a;
};
int A::_a = 1;
int main()
{A aa;aa.Print();return 0;
}

在这里插入图片描述

  • 非静态成员变量不能在类的外部定义
    在这里插入图片描述

  • 静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区

  • 用static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针,不能访问非静态成员变量。

#include<iostream>
using namespace std;
class A {
public://静态成员不能在类里面初始化/*A(int i = 1):_a(i){}*/void Print() const{cout << _a << endl;}/*static int get(){return _b;//静态成员函数没有this指针,不能访问非静态成员变量}*/
private:static int _a;int _b;
};
int A::_a = 1;
int main()
{A aa;aa.Print();return 0;
}

在这里插入图片描述

  • 静态成员函数中可以访问其他的静态成员,但是不能访问非静态的,因为没有this指针
  • 非静态的成员函数,可以访问任意的静态成员变量和静态成员函数
  • 突破类域就可以访问静态成员,可以通过类名::静态成员或者对象.静态成员来访问静态成员变量和静态成员函数。
#include<iostream>
using namespace std;
class A {
public:void Print() const{cout << _a << " " << _b << endl;}static int get(){return _a;}
public:static int _a;
private:int _b = 2;
};
int A::_a = 1;
int main()
{A aa;cout << A::_a << endl;cout << aa._a << endl;cout << A::get() << endl;cout << aa.get() << endl;return 0;
}
  • 静态成员也是类的成员,受public、protected、private访问限定符的限制
    在这里插入图片描述
    在这里插入图片描述
    可以看到,不管是静态成员变量还是静态成员函数,它们都受public、protected、private访问限定符的限制。

  • 静态成员变量不能在声明位置给缺省值初始化,因为缺省值是给构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表。

在这里插入图片描述

练习

设已经有A,B,C,D 4个类的定义,程序中A,B,C,D 4个类的构造函数和析构函数的调用顺序是什么?

#include<iostream>
using namespace std;
class A {
public:A(int i = 1):a(i){cout << "A()" << endl;}~A(){cout << "~A()" << endl;}
private:int a;
};
class B {
public:B(int i = 1):b(i){cout << "B()" << endl;}~B(){cout << "~B()" << endl;}
private:int b;
};
class C {
public:C(int i = 1):c(i){cout << "C()" << endl;}~C(){cout << "~C()" << endl;}
private:int c;
};
class D {
public:D(int i = 1):d(i){cout << "D()" << endl;}~D(){cout << "~D()" << endl;}
private:int d;
};
C c;
int main()
{A a;B b;static D d;return 0;
}

我们先来看结果:
在这里插入图片描述

构造函数的调用顺序:全局区域——>局部区域(在局部区域,不管是静态对象还是非静态对象,谁先调用构造就先构造谁)

析构函数的调用顺序:局部区域——>静态区——>全局区域(在局部区域,后构造的先析构)

四. 友元

概念

在C++中,友元(friend)是一种特殊的类成员或函数,它不属于类的成员,但可以访问类的私有(private)和保护(protected)成员。友元提供了一种机制,使得某些特定的函数或类可以访问类的内部数据,即使这些数据是私有的或受保护的。

友元提供了一种突破类访问限定符封装的方式友元分为:友元函数和友元类,在函数声明或者类声明的前面加 friend,并且把友元声明放到一个类的里面

友元函数:一个非成员函数可以被声明为某个类的友元,这样它就可以访问该类的所有私有和保护成员。友元函数的声明通常放在类的内部,但定义通常在类定义之外。

class MyClass {
private:int privateVar;
public:void setPrivateVar(int value) { privateVar = value; }friend void myFriendFunction(MyClass& obj);
};void myFriendFunction(MyClass& obj) {// 可以访问obj的私有成员obj.privateVar = 10;
}

友元类:一个类可以被声明为另一个类的友元,这样友元类的所有成员函数都可以访问声明它的类的私有和保护成员。

class MyClass {
private:int privateVar;
public:friend class MyFriendClass;
};class MyFriendClass {
public:void accessPrivateVar(MyClass& obj) {// 可以访问obj的私有成员obj.privateVar = 20;}
};

特性

  • 外部友元函数可访问类的私有和保护成员,友元函数仅仅是一种声明,他不是类的成员函数。
#include<iostream>
using namespace std;class A
{// 友元声明friend void func(const A& aa);
private:int _a1 = 1;int _a2 = 2;
};void func(const A& aa)
{cout << aa._a1 << " " << aa._a2 << endl;
}int main()
{A aa;func(aa);return 0;
}
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
  • 一个函数可以是多个类的友元函数。
#include<iostream>
using namespace std;// 前置声明,否则A的友元函数声明时编译器不认识B
class B;class A
{// 友元声明friend void func(const A& aa, const B& bb);
private:int _a1 = 1;int _a2 = 2;
};class B
{// 友元声明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 << bb._b1 << endl;
}
int main()
{A aa;B bb;func(aa, bb);return 0;
}
  • 友元类中的成员函数都可以是另一个类的友元函数,都可以访问另一个类中的私有和保护成员
#include<iostream>
using namespace std;
class A
{// 友元声明friend class B;
private:int _a1 = 1;int _a2 = 2;
};
class B
{
public:void func1(const A& aa){cout << aa._a1 << endl;cout << _b1 << endl;}void func2(const A& aa){cout << aa._a2 << endl;cout << _b2 << endl;}
private:int _b1 = 3;int _b2 = 4;
};
int main()
{A aa;B bb;bb.func1(aa);bb.func2(aa);return 0;
}
  • 友元类的关系是单向的,不具有交换性,比如A类是B类的友元,但是B类不是A类的友元
  • 友元类关系不能传递,如果A是B的友元,B是C的友元,但是A不是C的友元
  • 友元有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用

五. 内部类

概念

如果一个类定义在另一个类的内部,这个在类内部的类就叫做内部类。内部类是一个独立的类,跟定义在全局相比,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。

定义方式:内部类定义在外部类的内部,就像外部类的成员一样。

#include<iostream>
using namespace std;
class A {
public:class B {private:int _i = 3;int _j = 4;};
private:int _i = 1;int _j = 2;
};
int main()
{cout << sizeof(A) << endl;return 0;
}

特性

  • 内部类默认是外部类的友元类。内部类可以直接访问外部类的公共、保护和私有成员。外部类则不是内部类的友元
#include<iostream>
using namespace std;
class A
{
private:int _q = 2;int _h = 1;
public:class B // B默认就是A的友元{public:void foo(const A& a){cout << a._q << endl;cout << a._h << endl;}};
};
int main()
{//因为类B在类A里面,受到类域的限制,要实例化出一个B类型的对象,必须突破类域//需要使用域作用限定符::A::B b;A aa;b.foo(aa);return 0;
}
  • 内部类可以直接访问外部类的静态成员变量
#include<iostream>
using namespace std;
class A
{
private:static int _k;int _h = 1;
public:class B // B默认就是A的友元{public:void foo(const A& a){cout << a._k << endl;cout << a._h << endl;}//可以直接访问外部类的静态成员变量void print(){cout << _k << endl;}};
};
int A::_k = 1;
int main()
{cout << sizeof(A) << endl;A::B b;A aa;b.foo(aa);b.print();return 0;
}
  • 内部类本质也是一种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使用,那么可以考虑把A类设计为B的内部类,如果内部类使用访问限定符修饰(private/protected),那么A类就是B类的专属内部类,其他地方都用不了。

六. 匿名对象

概念

在C++中,匿名对象通常指的是没有名字的对象这种对象通常是临时的,并且只在创建它们的表达式中有效

用类型(实参)定义出来的对象叫做匿名对象,相比之前我们定义的类型对象名(实参)定义出来的叫有名对象。

#include<iostream>
using namespace std;
class A
{
public:A(int i = 1):_a(i){cout << "A(int i)" << endl;}~A(){cout << "~A()" << endl;}private:int _a;
};
int main()
{A a;A();return 0;
}

特性

  • 匿名对象生命周期只在当前一行,当编译器读到下一行代码时,匿名对象就会被自动销毁。一般临时定义一个对象当前用一下即可,就可以定义匿名对象。

在这里插入图片描述

  • 匿名对象可以调用它的成员函数
#include<iostream>
using namespace std;
class A
{
public:A(int i = 1):_a(i){cout << "A(int i)" << endl;}~A(){cout << "~A()" << endl;}int Get(int n){return n;}private:int _a;
};
int main()
{cout << A().Get(10) << endl;return 0;
}

在这里插入图片描述

  • 匿名对象可以作为参数传递给函数
#include<iostream>
using namespace std;
class A
{
public:A(int i = 1):_a(i){cout << "A(int i)" << endl;}~A(){cout << "~A()" << endl;}int Get(int n){return n;}private:int _a;
};
void Func(A a)
{}
int main()
{Func(A());return 0;
}

同时,匿名对象也可以作为函数参数的缺省值

void Func(A a = A())
{}
  • 匿名对象的引用

匿名对象是临时的,具有常性,想引用一个匿名对象时必须使用const引用(权限的平移)。使用const引用,我们可以确保引用不会修改源对象,同时延长了对象的生命周期,使其在整个程序运行期间都有效。这是因为const引用本身不会创建新的存储空间,而是直接引用原始对象。

#include<iostream>
using namespace std;
class A
{
public:A(int i = 1):_a(i){cout << "A(int i)" << endl;}~A(){cout << "~A()" << endl;}int Get(int n){return n;}private:int _a;
};
int main()
{A aa;const A& a = A();cout << "----------" << endl;return 0;
}

在这里插入图片描述
可以看到,通过const引用了一个匿名对象,const绑定到了匿名对象上使其生命周期延长,所以匿名对象不会被立马销毁。

如果不使用const引用,编译器就会报错,如下:
在这里插入图片描述

七. 对象拷贝时的编译器优化

1.现代编译器会为了尽可能提高程序的效率,在不影响正确性的情况下会尽可能减少一些传参和传返回值的过程中可以省略的拷贝。
2.如何优化C++标准并没有严格规定,各个编译器会根据情况自行处理。当前主流的相对新一点的编译器对于连续一个表达式步骤中的连续拷贝会进行合并优化,有些更新更"激进"的编译器还会进行跨行跨表达式的合并优化。

#include<iostream>
using namespace std;
class A
{
public:A(int a = 0):_a1(a){cout << "A(int a)" << endl;}A(const A& aa):_a1(aa._a1){cout << "A(const A& aa)" << endl;}A& operator=(const A& aa){cout << "A& operator=(const A& aa)" << endl;if (this != &aa){_a1 = aa._a1;}return *this;}~A(){cout << "~A()" << endl;}
private:int _a1 = 1;
};void f1(A aa)
{}
A f2()
{A aa;//cout << &aa << endl;return aa;
}
int main()
{//vs2019: 1构造一个临时对象A(1),临时对象再拷贝构造aa1,此时1隐式类型转换为临时对象//vs2022: 此时1隐式类型转换为临时对象A(1),相当于A aa1 = A(1);//为了避免拷贝,编译器优化为直接构造aa1,调用A aa1(1);A aa1 = 1;//传递实参aa1,拷贝构造aaf1(aa1);cout << endl;f1(1);// 隐式类型转换f1(A(1));// 显示调用,传匿名对象cout << endl;//vs2019: 构造+拷贝构造//vs2022: 直接构造(直接构造临时对象A())f2();cout << endl;//vs2019: 连续拷贝构造+拷贝构造->优化为一个拷贝构造//vs2022: 直接优化为直接构造,f2()中的aa不构造,构造aa2,并且aa是aa2的别名//aa和aa2的地址一样(在同一块内存空间),aa不会随着f2()的销毁而被析构A aa2 = f2();//cout << &aa2 << endl;cout << endl;//vs2019: 遇到连续拷贝构造+赋值重载->无法优化//vs2022: f2()可优化(直接构造),赋值重载无法优化aa1 = f2();cout << endl;return 0;
}

vs2019编译器(Debug)
在这里插入图片描述

vs2022编译器(Debug)
在这里插入图片描述
可以看到,版本越新的编译器优化得越好。

END

对以上内容有异议或者需要补充的,欢迎大家来讨论!

相关文章:

C++类和对象 (下)

文章目录 前言一. 再探构造函数初始化列表特性总结练习 二. 类型转换2.1 隐式类型转换2.2 临时对象具有常性2.3 explicit关键字2.4 多参数类型转化 三. static成员概念特性练习 四. 友元概念特性 五. 内部类概念特性 六. 匿名对象概念特性 七. 对象拷贝时的编译器优化END 前言 …...

网络层5——IPV6

目录 一、IPv6 vs IPv4 1、对IPv6主要变化 2、IPv4 vs IPv6 二、IPv6基本首部 1、版本——4位 2、通信量类——8位 3、流标号——20位 4、有效载荷长度——16位 5、下一个首部——8位 6、跳数限制——8位 7、源 、 目的地址——128位 8、扩展首部 三、IPv6地址 1…...

【wpf】ResourceDictionary 字典资源的用法

如果你的字典资源是写在启动项目的App.xaml里 <Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source"pack://application:,,,/YourNonStartupProject;component/Resources/SharedResour…...

Foliate:沉浸式阅读!!!

项目简介 Foliate 是一款开源的电子书阅读器&#xff0c;专为现代操作系统设计&#xff0c;提供了优雅且实用的阅读体验。它支持多种电子书格式&#xff0c;包括 EPUB、Mobipocket、Kindle、FB2、CBZ 和 PDF&#xff0c;让用户能够以分页或滚动模式阅读。Foliate 允许用户自定义…...

【excel基本操作-sumif绝对引用和相对引用

低量级数据的存储 复杂且无法优化的数据报表 怎么学excel? 一、输入与输出 二、计算与处理 三、可视化 四、连接匹配与自动化 excel操作笔记 打开表格第一步筛选 所以筛选的快捷键&#xff1a;shiftctrll 排序&#xff1a;多列排序 开始-排序与筛选-自定义排序-设置关键字添…...

word及Excel常见功能使用

最近一直在整理需规文档及表格&#xff0c;Word及Excel需要熟练使用。 Word文档 清除复制过来的样式 当复制文字时&#xff0c;一般会带着字体样式&#xff0c;此时可选中该文字 并使用 ctrlshiftN 快捷键进行清除。 批注 插入->批注&#xff0c;选中文本 点击“批注”…...

网页中的某个元素高度突然无法设置

做网页时本来一个div的高度好好的&#xff0c;结果代码打着打着突然发现有个div的高度变的很小&#xff0c;把我很多在这个div里的元素给搞的看不见了。 找了好久的原因最后发现是这个div的结束标签</div>不小心被我删了,之后把这个</div>给补上就好了。...

springboot给不同用户动态定制请求结果思路

我有个朋友在公司遇到一个需求&#xff1a;某个接口&#xff0c;面向不同的用户返回的字段数不一样字段数。 我举例两种场景并且都给一个方案他&#xff0c;同时也供大家参考。 场景1&#xff1a; 接口返回的是List 或者直接就是entity&#xff0c;且entity对应某张数据表&…...

【网络】HTTP(超文本传输协议)详解

目录 引言一、HTTP的基本概念1.1 什么是HTTP&#xff1f;1.2 HTTP的工作流程1.3 HTTP工作流程图 二、HTTP请求与响应2.1 HTTP请求格式2.2 HTTP响应格式 三、常见的HTTP状态码3.1 其他状态码示例 四、HTTP版本的演变4.1 HTTP/1.04.2 HTTP/1.14.3 HTTP/24.4 HTTP/3 五、HTTP的安全…...

poll()方法和remove()方法的区别是什么?

在Java的集合框架中&#xff0c;poll()方法和remove()方法是两个常用于从队列&#xff08;Queue&#xff09;头部获取并移除元素的方法。尽管它们的作用相似&#xff0c;但在行为细节和适用场景上存在显著的区别。以下是对这两个方法区别的详细阐述&#xff0c;旨在帮助开发者更…...

小程序跳转另一个小程序

1.配置要跳转的appid和小程序页面路径 wx.navigateToMiniProgram({appId: 目标小程序appid,path: 目标小程序页面路径,//develop开发版&#xff1b;trial体验版&#xff1b;release正式版envVersion: release, success(res) {// 打开成功console.log("跳转小程序成功&…...

介绍一下数组(c基础)(详细版)

c初期&#xff0c;记住规则&#xff0c;用规则。 我只是介绍规则。&#xff08;有smart版&#xff09; 数组 arr 看成一个集合但元素有次序了。 如何计算数组的大小-CSDN博客 简单讲解一下strlen与sizeof&#xff08;c基础&#xff09;-CSDN博客 arr[n] { }; [ ] 下标引…...

工业主板在汽车制造中的应用

工业主板在汽车制造中的应用非常广泛&#xff0c;主要得益于其高稳定性、高集成性、以及强大的计算和处理能力。以下是对工业主板在汽车制造中应用的详细分析&#xff1a; 一、应用场景 自动驾驶车辆&#xff1a; 工业主板作为自动驾驶车辆的核心计算平台&#xff0c;负责处…...

博弈论(所有情况最优解)——课堂笔记

博弈论(所有情况最优解)——课堂笔记|【博弈论】分割数游戏-CSDN博客https://blog.csdn.net/back_room/article/details/143464453?spm=1001.2014.3001.5501【博弈论】拍卖土地-CSDN博客...

深入提升Python编程能力的全方位指南

Python作为一种强大且灵活的编程语言&#xff0c;广泛应用于数据科学、机器学习、网络开发、自动化等领域。提升Python编程技术需要结合多方面的知识和技能。本文将详细介绍通过掌握核心技术、项目实践和代码示例来系统提升Python编程技能的方法。 一、掌握基础和高级Python特…...

如何使用 Python 语言的正则表达式进行网页数据的爬取?

以下是使用 Python 语言的正则表达式进行网页数据爬取的一般步骤&#xff1a; 一、安装必要的库&#xff1a; requests&#xff1a;用于发送 HTTP 请求获取网页内容。可以使用 pip install requests 命令进行安装。re&#xff1a;Python 的内置正则表达式库&#xff0c;用于对…...

剑指offer第七、八天

1.矩阵中的路径 class Solution {int n, m;int dx[4]{ 1,-1,0,0 };int dy[4]{ 0,0,1,-1 };bool dfs(int i, int j, vector<vector<char> >mat,vector<vector<bool> >vis, int u, const char* str){if (u strlen(str)-1){//刚开始这里我用的是strlen(…...

有哪些常见的方法可以评估中断处理能力?

以下是一些常见的评估中断处理能力的方法: 基准测试(Benchmarking) 定义和原理:基准测试是通过运行一系列标准化的测试程序来衡量系统性能的方法。对于中断处理能力评估,可以使用专门设计的中断基准测试软件。这些软件会模拟各种中断场景,如不同频率、不同优先级的中断请…...

Android GPU纹理数据拷贝

在 Android 开发中读取纹理数据有以下几种方法&#xff1a; glReadPixelsImageReaderPBO&#xff08;Pixel BufferObject&#xff09; HardwareBuffer 1. glReadPixels glReadPixels 是 OpenGL ES 的 API&#xff0c;通常用于从帧缓冲区中读取像素数据&#xff0c;OpenGL ES…...

浏览器端直播推流实现——系统篇

浏览器端用vue3.5.12写,服务器端用php8.2+swoole5.1.4+thinkphp8写,流媒体服务器使用nginx-rtmp模块,拉流App端用uniapp(其他端各自实现吧,这里以App端为例) 操作系统基于opencloudos8,还用到了ffmpeg,该安装就安装,这里不啰嗦安装步骤 以下是vue的代码,比较简陋,各…...

HDFS和HBase跨集群数据迁移 源码

HDFS集群间数据迁移&#xff08;hadoop distcp&#xff09; hadoop distcp \ -pb \ hdfs://XX.14.36.205:8020/user/hive/warehouse/dp_fk_tmp.db/ph_cash_order \ hdfs://XX.18.32.21:8020/user/hive/warehouse/dp_fksx_mart.db/HBase集群间数据&#xff08;hbase ExportSnap…...

opencv实时弯道检测

项目源码获取方式见文章末尾&#xff01; 600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于CNN-RNN的影像报告生成】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实现…...

计算机网络综合题

IP数据报的划分 CRC差错检测 冗余码的计算 因此&#xff0c;余数是1110&#xff0c;传输的数为11010110111110。在传输过程中最后两位变成o&#xff0c;接收端能够发现&#xff0c;因为11010110111110除以10011余数不为0。 子网划分 暴力求解法 &#xff08;定长子网划分大量…...

【ARM Linux 系统稳定性分析入门及渐进 1.2 -- Crash 工具依赖内容】

请阅读:【Linux 维测及Crash使用专栏】 文章目录 Prerequisites1. 内核对象文件2. 内存镜像3. 平台处理器类型4. Linux 内核版本 Prerequisites crash 工具需要依赖下面的内容&#xff1a; 1. 内核对象文件 vmlinux 文件&#xff1a;需要一个 vmlinux 内核对象文件&#xff…...

「C/C++」C++标准库 之 #include<exception> 异常处理库

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…...

YOLOv7-0.1部分代码阅读笔记-experimental.py

experimental.py models\experimental.py 目录 experimental.py 1.所需的库和模块 2.class CrossConv(nn.Module): 3.class Sum(nn.Module): 4.class MixConv2d(nn.Module): 5.class Ensemble(nn.ModuleList): 6.def attempt_load(weights, map_locationNone): 1…...

【大数据学习 | kafka】简述kafka的消费者consumer

1. 消费者的结构 能够在kafka中拉取数据进行消费的组件或者程序都叫做消费者。 这里面要涉及到一个动作叫做拉取。 首先我们要知道kafka这个消息队列主要的功能就是起到缓冲的作用&#xff0c;比如flume采集数据然后交给spark或者flink进行计算分析&#xff0c;但是flume采用的…...

系统架构设计师论文:论湖仓一体架构及其应用

试题四 论湖仓一体架构及其应用 随着5G、大数据、人工智能、物联网等技术的不断成熟,各行各业的业务场景日益复杂,企业数据呈现出大规模、多样性的特点,特别是非结构化数据呈现出爆发式增长趋势。在这一背景下,企业数据管理不再局限于传统的结构化 OLTP (On-Line Transact…...

电磁兼容(EMC):GB 4343.1喀呖声 详解

目录 1. 喀呖声的危害 2. 喀呖声 Click定义 3. 中频参考电平 4. 开关操作 5. 最小观察时间 6. 喀呖声率 7. 喀呖声限值 8. 上四分位法 1. 喀呖声的危害 喀呖声作为一种电压骚扰&#xff0c;其危害主要体现在以下几个方面&#xff1a; 对电子设备的干扰&#xff1a;喀呖…...

纯血鸿蒙Native层支持说明

本文所有描述均参考鸿蒙官方文档&#xff1a;传送门 1.对C库的支持 C标准函数库在C语言程序设计中&#xff0c;提供符合标准的头文件&#xff0c;以及常用的库函数实现&#xff08;如I/O输入输出和字符串控制&#xff09;。 HarmonyOS采用musl作为C标准库&#xff0c;musl库…...