【C++初阶】之类和对象(下)

2024-04-05 7684阅读

【C++初阶】之类和对象(下)

  • ✍ 再谈构造函数
    • 🏄 初始化列表的引入
      • 💘 初始化列表的语法
      • 💘 初始化列表初始化元素的顺序
      • 🏄 explicit关键字
      • ✍ Static成员
        • 🏄 C语言中的静态变量
        • 🏄 C++中的静态成员
        • 🏄 特性
        • ✍ 友元
          • 🏄 友元函数
          • 🏄 友元类
            • 💘 友元类的特性
            • ✍ 内部类
              • 🏄 内部类的特性
              • ✍ 匿名对象
              • ✍ 拷贝对象时的一些编译器优化
                • 🏄 隐式类型,连续的构造+拷贝构造->优化为直接构造
                  • 💘 隐式类型生成的对象具有常性
                  • 🏄 一个表达式中,连续的构造+拷贝构造->优化为一个构造
                  • 🏄 一个表达式中,连续的拷贝构造+拷贝构造->优化一个拷贝构造
                  • 🏄 一个表达式中,连续的拷贝构造+赋值重载->无法优化
                  • 🏄 Release下不是一个表达式的连续的构造+拷贝构造-->构造函数(部分会优化)
                  • ✍ 再次理解类和对象
                    • 🏄 类和对象的理解
                    • 🏄 类的组成

                      【C++初阶】之类和对象(下) 第1张

                      📃博客主页: 小镇敲码人

                      💞热门专栏:C++初阶

                      🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏

                      🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月,独傲天下百坚强。 男儿应有龙腾志,盖世一意转洪荒。 莫使此生无痕度,终归人间一捧黄。🍎🍎🍎

                      ❤️ 什么?你问我答案,少年你看,下一个十年又来了 💞 💞 💞

                      前言:本篇博客接上篇类和对象中。接着来跟着博主学习C++类和对象下的一些特性吧!

                      ✍ 再谈构造函数

                      构造函数体类的操作我们只能叫做赋值,不能叫做初始化,因为初始化只有一次,而赋值可以在构造函数体类无数次。

                      假设现在我们的类里面有const成员和引用成员,会发生什么情况呢?

                      【C++初阶】之类和对象(下) 第2张

                      奇怪这里我们明明在构造函数内给year和month赋值了呀,为什么还是会报错呢?报错说我们没有初始化,说明初始化并不发生在构造函数内。

                      我们来回顾一下,const对象和引用必须在定义的时候就初始化:

                      【C++初阶】之类和对象(下) 第3张

                      但是在类里面它们只是声明了一下而已,并没有定义,真正定义是在那个类实例化一个对象之后。而且const对象和引用在初始化之后就不能修改了,这样你应该就可以理解,为什么不允许在构造函数体类初始化这些对象了,因为我无法判断你是否第二次又对它进行了初始化(如果真那样做就逻辑不自洽了)。

                      🏄 初始化列表的引入

                      那不能在构造函数函数体里面初始化在哪里初始化呢?答案是在初始化列表里面初始化。

                      💘 初始化列表的语法

                      class Date
                      {
                      public:
                      	Date(int month_):year(3),month(month_),day(2)
                      	{
                      	}
                      private:
                      	const int year;
                      	int& month;
                      	int day ;
                      };
                      

                      在原先的普通构造函数的函数名后面加上冒号,然后对应的成员变量后面加括号,括号里面是其要初始化的值,不同变量间使用逗号分隔。

                      注意如果是const对象或者引用类型的初始化必须走初始化列表,拷贝构造函数也可以用来创建一个对象,这些类型也必须走初始化列表,否则就会报错。

                      【C++初阶】之类和对象(下) 第4张

                      这里就算我们使用了初始化列表,编译器隐式生成的拷贝赋值函数也会被删除。

                      【C++初阶】之类和对象(下) 第5张

                      除了const和引用类型的变量必须走初始化列表,没有无参的构造函数的自定义类型也必须走初始化列表(因为要给它传参数),也不能放在构造函数中,因为自定义类型的构造函数只能在初始化的时候调用。

                      有无参的构造函数(可以访问)的自定义类型会在定义的时候自动调用:

                      【C++初阶】之类和对象(下) 第6张

                      没有无参的构造函数时,如果你不再初始化列表里调用,就会报错:

                      【C++初阶】之类和对象(下) 第7张

                      这个时候我们应该在定义的时候给这个自定义类型传一个参数:

                      【C++初阶】之类和对象(下) 第8张

                      💘 初始化列表初始化元素的顺序

                      这个顺序与我们实际在初始化列表中的元素初始化顺序无关,只与元素的声明顺序有关。

                      【C++初阶】之类和对象(下) 第9张

                      【C++初阶】之类和对象(下) 第10张

                      🏄 explicit关键字

                      explicit关键字可以防止只需要传一个参数(只有一个或者后面都是缺省参数)的普通的构造函数发生隐式类型的转换。

                      请看下面代码:

                      class Date
                      {
                      public:
                           Date(int year_)
                      	{
                      		year = year_;
                      		month = 3;
                      		day = 2;
                      	}
                      	~Date()
                      	{
                      	}
                      private:
                      	int year;
                      	int month;
                      	int day ;
                      };
                      int main()
                      {
                      	
                      	Date y(2023);
                      	y = 2022;
                      	return 0;
                      }
                      

                      你是否会认为其会导致编译错误呢,其实不然,这里编译器会将2022隐式类型转化为Date类型,我们可以通过调试发现其确实调用了构造函数:

                      【C++初阶】之类和对象(下) 第11张

                      并且y的year变成了2022,这里是先调用了一次构造函数,再去调用了编译器默认生成的赋值构造函数。

                      【C++初阶】之类和对象(下) 第12张

                      如果我们在普通构造函数前加上explicit就不支持隐式类型转换了。

                      【C++初阶】之类和对象(下) 第13张

                      ✍ Static成员

                      🏄 C语言中的静态变量

                      我们在C语言里面也有Static类型的变量,我们把它称作静态成员变量,这个变量有一个特征,就算出了函数作用域,它不会销毁,生命周期只有程序结束它才会结束。

                      void f()
                      {
                      	static int a = 3;
                      	int b = 3;
                      	a++;
                      	b++;
                      }
                      int main()
                      {
                      	f();
                      	f();
                      	return 0;
                      }
                      

                      连续调用两次f()函数a为多少呢?

                      【C++初阶】之类和对象(下) 第14张

                      可以看到a变成了5,说明a执行了两次++,在第一次出函数后,它没有销毁,并且静态变量只会定义一次。

                      🏄 C++中的静态成员

                      在c++的类里面也会有静态的成员,它和C语言中的函数中的静态变量有什么区别和相同之处呢呢?

                      C++类里面有两类静态成员,它们是静态成员函数和静态成员变量。

                      class Date
                      {
                      	Date()
                      	{
                      		count++;
                      	}
                      	Date(const Date& x)
                      	{
                      		count++;
                      	}
                      	static int Getcount()
                      	{
                      		return count;
                      	}
                      	~Date()
                      	{
                      		count--;
                      	}
                      private:
                      	static int count;
                      };
                      int Date::count = 0;
                      int main()
                      {
                      	return 0;
                      }
                      

                      上述程序可以用来计算类实例化了多少个对象。下面外面来具体阐述一下它们的特性。

                      🏄 特性

                      1. 静态成员函数和静态成员变量也受访问限定符的限制。
                      2. 静态成员变量必须要在类外面初始化,初始化不要求访问限定符为public,但是下次调用的时候需要它在类外面可以访问,且不能多次初始化。

                        【C++初阶】之类和对象(下) 第15张

                      3. 静态成员变量不能在声明的时候给缺省值,因为它的初始化不走初始化列表,而是在类外面通过类名+::进行访问并初始化。

                      【C++初阶】之类和对象(下) 第16张

                      4、静态成员函数和静态成员变量在类外面访问(假设是公有的),可以通过实例化对象访问或者是类名+::访问。

                      【C++初阶】之类和对象(下) 第17张

                      5. 静态成员(变量和函数)为所有类对象所共享,不属于某个具体的对象,存放在静态区。

                      6. 静态成员函数类没有this指针,不能访问任何非静态成员,但是可以访问静态成员。

                      【C++初阶】之类和对象(下) 第18张

                      7. 但是非静态的成员函数可以调用静态成员。

                      【C++初阶】之类和对象(下) 第19张

                      想一想为什么需要静态函数呢?就拿刚刚计算实例化了多少对象的程序来说,想知道没有实例化对象时count为多少,如何知道呢?此时不能实例化对象且count为private,就只能借助于类的静态成员函数来完成。

                      ✍ 友元

                      友元提供了一种突破访问限定符和类域限定符的作用,但是破坏了程序的耦合度,不易过多使用,友元分为友元函数和友元类。

                      🏄 友元函数

                      如果一个函数是一个类的友元函数,那么它就可以访问这个类的私有成员。

                      友元函数是为了解决重载 public: Date() { year = 2022; month = 2; day = 1; } void operator } private: int year; int month; int day; }; int main() { Date x; std::cout public: friend std::ostream& operator year = 2022; month = 2; day = 1; } private: int year; int month; int day; }; std::ostream& operator cout_ Date x; std::cout // 声明类A为B的友元类,这样A可以访问B的私有和保护成员 friend class A; public: // 公共成员函数ff,可以在类的外部调用 void ff() { // 函数体为空,没有实际功能 } private: // 在类的私有部分不能声明友元类,友元声明应该放在类的公有或保护部分 // 私有成员函数f,只能在B类内部或B的友元中调用 void f() { // 函数体为空,没有实际功能 } // 私有整型成员变量a,初始化为3 int a = 3; // 私有整型成员变量b,初始化为4 int b = 4; }; // 定义一个名为A的类 class A { public: // 公共成员函数fff,可以在类的外部调用 void fff() { // 调用B类对象x的公共成员函数ff x.ff(); // 调用B类对象x的私有成员函数f // 由于A是B的友元类,所以可以访问B的私有成员 x.f(); } private: // A类中含有一个B类的对象x作为私有成员 B x; }; int main() { // 创建A类的对象y A y; // 程序正常结束,返回0 return 0; } public: // A类的构造函数 A() { // 构造函数体为空 } // A类的公有成员函数f void f() { // 函数体为空 } // A类的内部类B class B { public: // B类的公有成员函数f,接收一个A类的引用作为参数 void f(A& x) { // 输出A类对象的c成员变量和B类的静态成员变量count std::cout // 函数体为空 } // A类的静态整型成员变量count,用于在多个A类对象间共享数据 static int count; // A类的私有整型成员变量c,初始化为3 int c = 3; }; // 初始化A类的静态成员变量count,赋值为3 int A::count = 3; int main() { // 创建A类的内部类B的对象b A::B b; // 创建A类的对象a A a; // 调用B类对象b的公有成员函数f,并传入A类对象a的引用 b.f(a); // 程序正常结束,返回0 return 0; } public: Date() { std::cout std::cout Date x; Date (); return 0; } public: Date() { std::cout } ~Date() { std::cout Date y; Date x(y); Date z(Date ()); return 0; } public: Date(int year, int month = 2, int day = 1) ://普通的构造函数 year_(year), month_(month), day_(day) { cout cout year_ = x.year_; month_ = x.month_; day_ = x.day_; cout cout } int main() { f(3); return 0; } public: Date(int year, int month = 2, int day = 1) ://普通的构造函数 year_(year), month_(month), day_(day) { cout cout year_ = x.year_; month_ = x.month_; day_ = x.day_; cout cout } int main() { f(3); return 0; } public: Date(int year, int month = 2, int day = 1) ://普通的构造函数 year_(year), month_(month), day_(day) { cout cout year_ = x.year_; month_ = x.month_; day_ = x.day_; cout cout } int main() { f(Date(2022)); return 0; } public: Date(int year, int month = 2, int day = 1) ://普通的构造函数 year_(year), month_(month), day_(day) { cout cout year_ = x.year_; month_ = x.month_; day_ = x.day_; cout cout } Date f1() { Date x(2022); return x; } int main() { Date y = f1(); return 0; } public: Date(int year, int month = 2, int day = 1) ://普通的构造函数 year_(year), month_(month), day_(day) { cout cout year_ = x.year_; month_ = x.month_; day_ = x.day_; cout cout } Date f1() { Date x(2022); return x; } int main() { Date y(2023); y = f1(); return 0; } public: Date(int year, int month = 2, int day = 1) ://普通的构造函数 year_(year), month_(month), day_(day) { cout cout year_ = x.year_; month_ = x.month_; day_ = x.day_; cout cout } Date f1() { Date x(2022); return x; } int main() { f1(); return 0;


    免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

    目录[+]