类与对象概念的补充(类型转换,静态成员,友元,内部类,匿名对象,拷贝合并优化)

张开发
2026/4/15 3:27:50 15 分钟阅读

分享文章

类与对象概念的补充(类型转换,静态成员,友元,内部类,匿名对象,拷贝合并优化)
文章目录类型转换explicitstatic静态成员变量友元内部类匿名对象对象拷贝时的编译器优化类型转换C支持内置类型隐式转换为类类型对象需要有以相关内置类型为参数的构造函数会先将右值隐式构造为临时对象再拷贝或移动给左边变量类的对象之间也可以隐式转换也需要有相关的构造函数支持 C11之后也支持使用多参数进行隐式转换需要将参数列表用{}括起来 隐式转换的本质还是调用构造函数只是写起来更简洁右值-临时对象-左边变量的过程也会被编译器优化可以一步直接完成效率不低但是影响可读性explicit构造函数前加explicit修饰就可以禁止隐式类型转换classA{};classMyClass{public:MyClass(intx){}explicitMyClass(doubley){}MyClass(constAother){}MyClass(constAother,intx){}};intmain(){MyClass my_class110;//隐式转换直接调用构造函数// MyClass my_class2 3.14;//有对应的构造函数但是有explicit修饰不能隐式转换不合法MyClassmy_class3(3.14);//显示构造调用非常合法A a;MyClass my_class4a;//隐式转换调用合法MyClass my_class5{a,1};//调用响应的构造函数合法等价于MyClass my_class5(a,1);}static静态成员变量用static修饰的成员变量称为静态成员变量静态成员不属于某个对象而是属于整个类的所有对象共享不在某个对象的空间中存放在静态区静态成员一定要在类外初始化因为它不属于任何对象不能被构造函数初始化所以缺省值和初始化列表也不能用 静态成员函数不属于任何对象所以它也没有this指针没有this指针就不能访问其它非静态成员只能访问静态成员 非静态成员可以访问任何静态成员变量和函数 通过类域就可以访问静态成员比如类名静态成员或者对象.静态成员友元友元提供了一种突破访问限定符的方式分为友元函数和友元类在声明前加friend并放到本类的内部友元函数只是一种声明不是成员函数放在类内的任何位置都可以 一个函数或类可以时多个类的友元 友元类中的成员函数都是本类的友元函数可以访问本类的私有和保护成员 友元类的关系是单向的本类不一定是友元类的友元 由于会提高耦合度破坏封装不建议多用classMyClass;//先声明MyClass类不然程序按顺序执行下面友元类和友元函数不认识MyClassclassFriendClass{int_val10;public:voidfunc(MyClassmc){mc._val30;}};voidFriendFunc(MyClassmc){mc._val20;}classMyClass{friendvoidFriendFunc(MyClassmc);// 声明友元函数关系friendclassFriendClass;// 声明友元类关系int_val10;public:voidfunc(FriendClassfc){fc._val20;}};intmain(){MyClass my_class;FriendClass friend_class;FriendFunc(my_class);friend_class.func(my_class);//my_class.func(friend_class);//不可行MyClass不是FriendClass的友元}内部类定义在一个类内部的类叫做内部类是一个独立的类与全局类想比它只是受外部类的类域和访问限定符限制外部类定义的对象中不会包含内部类内部类默认为外部类的友元 本质也是一种封装当A类主要服务于B类时可以吧A类设计为B类的内部类 如果放到私有或保护域A就是B的专属内部类其它地方都不能用classMyClass// 外部类{private:int_val100;classInnerClass// 内部类默认就是外部类的友元{public:voidfunc(MyClassmc){mc._val200;// 内部类可以直接访问外部类私有成员}};public:InnerClass _in;//在公有域实例化一个内部类的对象如果不写这句MyClass类对象不会自动包含InnerClass类对象};intmain(){MyClass mc1;MyClass mc2;mc1._in.func(mc1);//调用mc对象的_in内部类对象的func函数mc1._in.func(mc2);//也可以对其它同类对象的内部类进行操作因为InnerClass类是整个MyClass类的内部类友元类}匿名对象类型实参定义出来的对象是匿名对象而平时用类型 对象名实参定义出来的叫有名对象匿名对象是临时对象生命周期只在当前这一行,包括这一行中间调用函数或跳转的各种过程classMyClass{public:MyClass(){}MyClass(intx){}voidfunc(){}};voidfunc(MyClassmc){}intmain(){MyClassmc(10);//有名对象生命周期与作用域相同MyClass(10);// 匿名对象生命周期只在这一行MyClass().func();func(MyClass(10));// 匿名对象常用来作为函数参数或者临时调用类中的某些函数MyClass mc1MyClass(10);//也可以用匿名对象来初始化一个新对象编译器会自动优化为直接构造MyClass mc(10);}对象拷贝时的编译器优化现代编译器为了尽可能提高程序的效率在不影响正确性的情况下会尽可能减少一些传参和传返回值的过程中的拷贝C标准没有严格规定优化方法各编译器的设定不同主流编译器会对一个表达式中的连续拷贝操作进行合并优化 有些更新的更激进的编译器还会进行跨行跨表达式的合并优化传参时如果是传值传参尽可能不要用有名对象传参而是用匿名对象或者类型转换方式传参更有利于编译器的合并优化classMyClass{public:MyClass(){}MyClass(constMyClassmc){}//拷贝构造};MyClassfunc(){MyClass temp;returntemp;}//返回值为MyClass类的函数intmain(){MyClass mcfunc();//理论过程应该是函数里创建了一个局部对象temp然后拷贝一份临时对象返回再将临时对象传给mc//新版编译器会自动优化为先将mc的地址传递给func然后func直接在mc的地址上创建temp省略拷贝操作//temp实际上就是mc不是引用或者指针二者是同一块内存空间}

更多文章