枫の个人主页
你不能改变过去,但你可以改变未来
算法/C++/数据结构/C
Hello,这里是小枫。C语言与数据结构和算法初阶两个板块都更新完毕,我们继续来学习C++的内容呀。C++是接近底层有比较经典的语言,因此学习起来注定枯燥无味,西游记大家都看过吧~,我希望能带着大家一起跨过九九八十一难,降伏各类难题,学会C++,我会尽我所能,以通俗易懂、幽默风趣的方式带给大家形象生动的知识,也希望大家遇到困难不退缩,遇到难题不放弃,学习师徒四人的精神!!!故此得名【C++游记】
话不多说,让我们一起进入今天的学习吧~~~
1>>再看构造函数
之前的构造函数还有一点点细节没说,今天咱再对它进行补充。
1.构造函数初始化还有一种方式,就是初始化列表。初始化列表以一个冒号开始,然后是一个个逗号进行分隔的数据成员列表,每个成员变量后跟一个括号中的初始值或者表达式。如_day(5),初始化天数为5。
2.每个成员变量在初始化列表中只能出现一次,也就是唯一性。初始化列表是所有成员变量定义初始化的地方。
3.有三类成员变量(引用、const、无默认构造)必须放在初始化列表进行初始化。
4.C++11支持成员变量在声明的时候给初始值,这个初始值主要是给没在初始化列表的成员变量使用的。
5.简单来说,能用初始化列表就用初始化列表进行初始化工作。
6.初始化列表按照成员变量在类中声明的顺序进行初始化,跟初始化列表顺序无关。
总结: 所有构造函数都有初始化列表。所有成员变量都要走初始化列表进行初始化。
#include<iostream>using namespace std;class D1 {public:D1(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){ }void print()const {cout << _year << " " << _month << " " << _day << endl;}private:int _year;int _day;int _month;};int main() {D1 a;a.print();return 0;}
结果为1 1 1 答案正确,这就是初始化列表啦~~
2>>static成员
降伏了初始化列表,接下来继续打static静态怪吧~
1.用static修饰的成员变量叫静态成员变量,静态成员变量一定要在类外面初始化。为什么?因为之前我们说过类独属一个域,静态成员变量在静态区,所以要在类外面初始化。
2.静态成员变量为所有类对象共享,不属于任何一个具体的对象。
3.静态成员函数没有this指针。
4.静态成员函数可以访问其他的静态成员,但不能访问非静态的,因为没有this指针。
5.非静态的成员函数,可以访问任意的静态成员变量和函数。
6.访问静态成员要突破类域,也就是类似于命名空间的类名::静态成员或对象名.静态成员来访问。
7.静态成员受访问限定符限制。
8.静态成员变量不能在声明位置初始化,因为它不属于任何一个对象。
#include<iostream>using namespace std;class D1 {public:D1(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){ }void print()const {cout << _year << " " << _month << " " << _day << endl;}private:int _year;int _day;int _month;static int person;//需要在类外初始化};int D1::person = 1;//初始化记得带上类名int main() {D1 a;a.print();return 0;}
3>>友元函数
打完static,又出现了友元怪,小怪好多呀~师傅加把劲!
1.友元是突破类域的一种方式,友元分为:友元函数和友元类。使用方式是在函数声明或者类声明前面加friend,还要把友元的声明放到一个类中。
2.外部友元函数可以访问类的私有和保护成员,它是一个声明,并不是类的成员函数。可以理解为非常好的朋友,你对我干什么都可以。
3.友元可以在类中任意位置定义。
4.一个函数可以是多个类的友元。
5.友元类中的成员函数都可以是另一个类的友元函数。
6.友元类的关系是单向的。我的友元函数是你,意味着你可以随意用我东西,但是我不能随意用你东西。
7.偶尔方便可以使用,但它会增加耦合度,破坏封装。
#include<iostream>using namespace std;class B;//必须有前置声明,否则A都不认识B,vb从上往下执行。class A {friend void print(const A& aa, const B& bb);//定义aa代替传进来的类变量,bb代替第二个类变量private:int _a1 = 11;int _a2 = 22;};class B {friend void print(const A& aa, const B& bb);//定义aa代替传进来的类变量,bb代替第二个类变量private:int _b1 = 111;int _b2 = 222;};void print(const A& aa, const B& bb) {//定义aa代替传进来的类变量,bb代替第二个类变量cout << aa._a1 << endl;cout << bb._b1 << endl;}int main() {A a;B b;print(a, b);return 0;}
#include<iostream>using namespace std;class A {friend class B;private:int _a1 = 11;int _a2 = 22;};class B {public:void print(const A& aa) {//定义aa代替传进来的类变量,因为A是B的友元,所以B可以访问A的成员变量cout << aa._a1 << endl;cout << _b1 << endl;}private:int _b1 = 111;int _b2 = 222;};int main() {A a;B b;b.print(a);return 0;}
4>>编译器的优化
最后的boos战,师傅加把劲!
1.编译器日新月异,在提高版本的过程中进行了一系列的优化,在不影响结果的情况下,会减少部分传参和传值的拷贝构造。
2.编译器的不同会进行不同的优化,连续的拷贝构造会合并成一个拷贝构造。
3.想看具体过程有两个办法,一是在Linux下关闭构造优化,命令为g++ test.cpp -fno-elide-constructors 二是使用较老的编译器,这时候都没有进行更新,也就没有优化的概念。
#include<iostream>using namespace std;class A {public:A(int a = 1):_a1(a){cout << "A(int a)" << endl;}A(const A& aa) :_a1(aa._a1)//拷贝构造的初始化列表{cout << "A(const A& aa)" << endl;}~A() {cout << "~A()" << endl;}private:int _a1 = 11;};void f1(A aa) {}int main() {//匿名对象,也就是直接给A赋值,生命周期只有这一行,构造一次,函数内右构造一次还要拷贝一次,然后析构f1(A(1));//连续的构造加拷贝构造会优化为一个构造return 0;}
5>>结语
今日C++到这里就结束啦,如果觉得文章还不错的话,可以三连支持一下。感兴趣的宝子们欢迎持续订阅小枫,小枫在这里谢谢宝子们啦~小枫の主页还有更多生动有趣的文章,欢迎宝子们去点评鸭~C++的学习很陡,时而巨难时而巨简单,希望宝子们和小枫一起坚持下去~你们的三连就是小枫的动力,感谢支持~