资讯详情

C++学习笔记(第二阶段汇总)

文章目录

  • 函数重载
    • 为什么要重载函数?
    • 如何重载函数?
    • 只传一个参
      • this->和 other.
      • 前面的.是class的.,后点是引用&的.
    • C 完全支持,java不支持,python有限度支持
      • C 并全支持并不是所有的支持
    • 运算符重载的本质是映射
    • 运算符重载在一定程度上反映了多态
    • 为什么返回值也是如此coordinate
    • 默认情况下,编译器提供了等号操作符重载
      • 为什么编译器默认提供等号运算符重载
      • 初始化与赋值的区别
      • 等号运算符重载和复制结构函数的优先级:优先复制结构函数
        • 赋值用于等号操作
          • 奇怪的一点:还打印出了拷贝构造的内容,原因:返回值值传参
          • 复制返回值传参复制时,调用复制结构函数
          • 引出返回值加入&提高效率
          • 返回值为变量,复制变量,返回值为对象,复制复制复制构造函数
          • 回到正题:复制构造函数初始化,等号赋值运算符重载
    • 自赋值
      • 地址是一样的,它带来了类似于深拷贝时的分析问题
      • 解决方法:直接return *this,直接用值
          • 为什么看到别人写等号载时,为什么会看到别人写条件判断?a=a时的情况
      • 加入返回值&提高效率
        • C 引用的发明来自这个等号运算符重载
    • C 没有默认的分析函数delete,所以一旦使用new手动写分析构函数
      • 数组的delete要加[]
      • \ \ a和a\ \ 运算符重载是一个特例,先跳过
  • 友元函数
    • 操作符重载的第二种方法:友元函数平行而不是主次函数
    • 什么时候用第二个友元函数写作?
      • c 并非所有人都能运算符重载
  • 静态类
    • c 没有静态类
    • 静态成员变量与普通成员变量的区别
      • 区别1:静态成员变量需要在类外重新定义
      • 区别2:静态成员变量可以在不创建对象的情况下使用
      • 区别3:静态成员变量创建的所有对象都指向同一个共享
        • 因此,静态成员不能初始化构造函数,也不能初始化类中的智能
          • 因此,静态成员变量不能初始化成员列表
    • 普通成员访问静态成员变量
    • 非静态成员变量和方法不能访问静态方法
      • 硬访问只能依靠传参,但已经非常间接了
          • 变量何时分配地址?
    • 从生命周期的角度来看,静态成员的变量和方法相当于整体变量
      • 换句话说,它是通过全局变量实现的
      • 普通成员的变量和方法更像是局部变量或堆申请的变量
      • 区别4:静态成员不占用类别中的内存。简单地说,它不在里面
        • 它似乎写在形式上,但实际上没有分配内存
        • 因为本质上它自身早就已经创建了内存了
    • 静态成员的用途
      • 静态成员变量的用途
        • 共享计数器
          • 也就是说,公共事物使用静态
      • 静态成员方法的用处
        • 在处理这些共同的东西时,使用静态方法
      • 静态类属于一种密封类
  • 无论放置多少友元函数public,private,protected都可以
  • 类的前置声明
  • 友元类
    • 友元类的缺点极大地破坏了面向对象,编译器无法帮助你消除错误
    • 不建议使用友元类和友元函数
      • 友元函数破坏了类的封装机制
  • 共有友元函数
  • 嵌套类(大部分时间不用)
  • 局部类
  • 数值转对象
    • 数值转向对象的本质
  • 模板
    • 多态静态多态运行和多态运行
      • 面向对象的多态是运行时的多态
    • 多态模板是静态多态模板
  • 模板类
  • 模板友元函数
  • 容器类
    • array容器类
  • using在C 第二种用法,跟随typedef差不多
  • 迭代器iterator
    • 迭代器是一种高水平的指针
    • begin和end的左闭右开
    • 逆向迭代器
  • vector容器
  • 为什么要预留位置?
    • 原因一:省钱
    • 原因二:减少内存碎片
  • 新的遍历方法for(auto &ch : s)
  • 泛型算法
    • 容器类本身包含少量泛型算法
    • 双向遗留迭代器
  • 函数对象
    • 关键是理解括号的运算符重载
  • 谓词
    • 函数对象可以用模板,但是函数不能用模板
      • 函数对象实现了静态局部变量的感觉
  • lamda表达式
    • 本质上是一个匿名函数
    • lamda函数只是写起来简便,但是效率并没有提高
    • 中括号是可以写东西的
  • 适配器
    • 适配器本质:是不同函数变成相同的传参个数
    • for each
  • 谓词补充:一元谓词和二元谓词
  • 模板的全特化和偏特化
    • 第二种偏特化的理解:特化成指针
    • 函数模板为什么不能偏特化:和函数重载功能一样,造成一定的尴尬冲突
    • 模板的全特化
      • 模板的全特化就已经是一个实例了,而模板的偏特化还不是实例
  • 迭代器萃取器
  • 三种适配器
    • 容器适配器
      • 从迭代器适配器理解C++为什么效率高
        • 大部分工作在编译期间就做好了
  • 顺序容器
  • 关联容器
    • 有序关联容器用二叉树和红黑树,无序关联容器用哈希表
    • 两大关联容器:set容器、map容器
    • set容器
      • 原地构造
    • map容器
  • 智能指针
    • 四种智能指针
    • share_ptr
    • weak_ptr配合share_ptr使用

函数重载

关于函数重载,它是在编译阶段就已经完成了,就是你这个过程叫做重载决策。

为什么要函数重载

这个运算符重在在c++里面,主要是因为它的面向对象的,那他不是单纯的变量的项相加相减的。举个例子,比如说a加B,他在面向对象里可能是person a + person b,那person的a+ b是什么呢?这个时候他就不是,不是一个普通的一加二加三这样的数字,它是一个两个对象的相加相减,这个时候的话就需要有运算符重载了,然后这个运算符重载呢,他是在一个,他是在那个person对象里面,你自己要给它定义的,你要自己给它定义一个person里面的a加B是什么意思。

之前的inta加B嘛,是a加B是比如说是数字相加,这个其实是我们所有人的共识,所以它在C加加啊,它C跟C加加编译器里面,他就自己就就它定义了这样的一个数字的相加吗?但是你如果是用person相加的话,这个的话不同有不同的看法嘛,所以这个时候你就不能够就没有达成一定的共识的。所以C跟C加加编译器,他不可能在底层帮你做项一加二等于三这样的一个运算符的处理,那你就要自己去定义自己去定义一个运算符存在,告诉自己定义person里面a加B是什么

如何函数重载

这个运算符重载,它有一个关键词叫operator,比如说你现在要定义一个坐标的相加吗?你这个坐标的类叫做coordinate Co operate,然后你,那么你一个坐标a加坐标B吧,然后他就是两个坐标相加,那还是返回值,还是一个坐标,所以你就在那个坐标的方法里面补上,补上一个方法,这个方法,返回值是coordinator,这个Co operate然后,然后再来一个。关键字,Operate,然后你再把那个你要进行的运算符存在,那符号写上去,这里是运算符存在加那么就写的,那么就写成operate加。注意这个运算符存在这个关键字,Operator是必须写的,这个是ci加里面帮你设计好了,你要用运算符存在就要写上这关键字。

这个你如果要用加号做运算符,那么你用operator加这个operator加你中间不能加空格了,Operator加是放在一起的,作为一个一块的,你operator跟加号之间不能有空格的。

然后你的那个重载运算符重载函数是这样写,coordinator operate+,然后括号,然后里面放你要传的参数,然后这里有个细节,因为你是只是把你的那个传进去,参数拿去运算,你不用改参数里面的值,所以你要加入cost,然后这还有一个细节,就是第二个细节,因为你这个里面你不希望他是复制吗?你希望他就直接改它的值,改成实参的值就是。不是,就是你希望用它实参的值,你不给你改,但是你希望直接用,你不希望直接不希望用来复制,所以你就用指针啊,这还有个细节,就是你可以不用指针,你用引用就行了,引用的话就是你传进去,它就只绑定那个那个那个变量了,它一辈子只绑定那个变量了,这个是引用跟指针的区别嘛,所以这就是变成cost coordinate &然后other。

只用传一个参

所以这里有个非常重要的细节,他传参只传了一个coordinate,就只传了一个coordinate and就是他只传了一个cos的coordinate and other吗?它这个就是说它有个本,就是有个主体跟次次要体的,一个一个一个一个理解,就是你的那个X跟X跟那个Y码是不是就是,也就是说你其中一个当does,当它这里面的用,然后其中另外一个你要加的那个当成其他的,就是a加B吗?你把a当成他这个里面本身的,那你就不用船餐,然后你把B当成他,令他他其他的要传进去的,当外面的那他,所以他只用传外面的那个,所以他只传了一个餐。

然后自己本身里面那个a呢,它用this去指向就可以了。

就是你传参的时候是不是传了一个coordinate类的这种类型的一个进去,那就是你要加的那个,然后就是假设说你要a加B,那么那个要加的那个,那个就是B,你要传的是B的那个那个东西进去,然后a你就不用传了,你就就你现在目前的这个类,你就把它当成B,所以只用传一个的。

this->和 other.

所以这里就是a加BC等于a加ba,就是B就是other,然后你要注意,这里this它是一个指针,所以它要用一个,所以它要用一个箭头,然后other,它用的它是个引用来的,所以它用的是点。

前面的.是class的.,后面的点是引用&的.

所以这里就变成temp.X等于does箭头X加上点点X,注意,这里的temp.X跟does箭头X跟other.X前后的两个点X的一些意义是完全不一样的。你那个前面那个temp d X,因为你temp定义的是一个考点,哪的类型的,他她是个class吗?那你可以理解为它也是个struck,那么这个struck的话呢,就是你会发现,就是你会发现这个东西就是就是一个结构体变量吗?所以它没有指向,没有定义结构体指针,没有定义它。你用的不是结构体的指针嘛,变量你用的是变量,所以你就是不点X,然后后面的R的点X呢,就不是这么理解的,它为什么用点,因为你这里传的参用的是引用,引用的话,它虽然是指针的一个简写嘛,但是它不是指针那种箭头方式,它有它的一个C加加的规则,引用的话就是用点去访问,所以就是的点X,所以前后两个点是不一样的意义的。

C++完全支持,java不支持,python有限度支持

关于这个运算符,重在C加加,它是完全支持的,但是Java它是不支持运算符存在的,然后python呢?它是有限度的支持运算符存在的。

C++完全支持也不是所有都支持

这个C加加全面支持,意思是大部分都是可以的,只有少量不可以,但也不是100%,每一个都可以,但是Java它是完全不支持的。

运算符重载的本质是映射

这个C加加的运算符存在本质上是有映射,你写一个operate,加他之后,你就可以映射到那个,直接变成一个家,比如说你是C等于a加B,是吧,他其实本质上是一个C等于a.operate加括号B,它是这样子的,那他就把那个operate加,然后括号那个映射成一个直接简,简化成一个加号,本质上是一种映射,那么Java他如果不支持这种运算符存在的话,他就只能是写成。C等于a.operate加括号B分号,然后这时候他可能在那个方法里面就不是写operate加,可能就是写ad了,反正总的意思就是说,它其实这两个本质上是一样的,只不就是ac等于a加B,跟这个跟这个C等于a加B,跟这个C等于a.operate加B是一样的意思,然后只不过C加加里面它可以支持operate的关键字,把它给重载,把它给重载成一个,把它给重载成一个C等于a加B简化掉,那Java就不行,Java你就只能用之前那种。

运算符重载一定程度体现多态

这个运算服从在从一定程度上体现了C加的多态性的思想,因为你比如说你在person类跟coordinate类是吧,这两个类里面,你如果都用了opera的加啊,代表了不同的含义,那么你在最后用的时候都是写的C等于a加B,那么你在a加B,你在不同的类里面代表的意思是不同的,那这个意思就是多肽了。

为什么返回值也要是coordinate

这里等号的赋值啊,有一个细节,就是它直接牵引,直接关系到你,为什么你要写函数的时候,直接写corda narrator Co or din aries冒号,冒号是不是正常来讲应该是void coordinate就行了,是吧,这个就涉及到你后面的,你这个等号的副职,可能会被另一个等号去用,所以比如说你他可能会变成be,等于括号C等于a,那么你等号里面的东西就要被C,等于a那个返回值要被逼给用掉。所以这个时候你就必须得要在前面设coordinary coordinary冒号,冒号,而不是void coordinate,你用了coordinary之后,你你在那个函数体里面,你就用你用个return新历史,你把你赋值之后的那个返回值的那个指针的取得里面的值就是星号,历史然后返回出来,那么这样呢,你就可以作为一个返回值去赋值,给另外一个等号了去。

那么这样它C等于a括号,它就可以又把它复制到另外一个B上面去,你如果没有写coordinate的话,你直接用Roy的冒号,冒号coordinate什么什么的话。

不是void冒号,冒号coordinary,就是你直接用void coordinate冒号,冒号的话,这样的话你就没你的返回值,就没有就没有返回值吧,没有返回值,那你最后你的B你的你的C等于a括号,这个东西就不能够再为别人用了。所以这个就是为什么你要会,后面会发现很多时候用的都是coordinate,然后coordinate,冒号冒号,然后里面return新历史为什么会这样用?

编译器默认提供了一个等号运算符重载了

这等号运算符你会发现很奇怪,就是它跟加号运算符不一样,你加号运算运算符,如果自己不写,那么它编译器就报错,但是你等号运算符,你自己不写,编译器没有报错,就说你如果,所以这,这从侧面说明啊,编译器它自己是给你写了一个默认的等号的运算符的等号的一个存在的,然后你如果是自己写了等号存在,它就用你人的等号啊,如果你没有自己写等号的话,那么它编译器它自己会给你用个默认的等号,它跟加号不一样的。

为什么编译器默认提供等号运算符重载-减轻工作量

这里解释一下为什么等号,他私家要给你做个默认的,但是其他的比如说加号啊,减号啊,加等于号啊,哪怕是大于小于号的一个判断,他都没有给你默认的,你要自己写等号,他给你默认了,为什么?他从一定程度上是帮你减轻了工作量,因为你实际代码中肯定大量会用到赋值的,这是肯定的,所以他需要他帮你减轻一定工作量,所以他就等号给你做个腹直等等号,给你做一个默认的,但是你如果要自己定义也可以,但实际上它本身给你提供了默认的,其他的他就没提供。

初始化和赋值的区别

初始化跟副词的区别,初始化呢,是说定义的同时进行一个赋值,这就叫初始化。但是你赋值的意思是说,你事先已经初,你是事先已经定义好了,你只是这里是副词而已。

也就是说你在定义一个东西的时候给他赋值,这个就不叫赋值,这个叫初始化,然后你再先是定义了之后,你后面在第二行上面再给他一个负值,这个就叫赋值。

等号运算符重载和拷贝构造函数的优先级:优先拷贝构造函数

这个等号的运算符存在啊,跟这个拷贝构造函数,它会优先使用拷贝构造函数,就是说比如说你用靠近瑞特B等于a,然后这个时候你会发现它调用的是拷贝构造函数,而不是说把那个等号给运算符从载掉,然后把那个a赋值给,把那个a初始化给B,他不是的,所以他不是把a复制,AB,它是用那个拷贝构造函数,它里面写了拷贝构造函数,用了拷贝构造函数了,所以他没有用等号,尽管你在那个类里面写等号的运算符存在,他也不用等号,运算符从载,他用的是拷贝构造函数。

赋值用的就是等号运算符重载

然后你如果不用初始化,单单用腹直就是你一个Co operate b,然后分号,第二行大写,B等于a,那么这个时候呢,就会发现他用的就是运算符存在的那个,那个打印,打印出来,就是那个等号运算符存在里面的信息,就说他有,他用了那个等号运算符存在了

奇怪的一点:还打印出了拷贝构造的内容,原因:返回值值传参

然后这里就很奇怪一点,他还打印了出来了那个拷贝构造函数里面的内容,这个是为什么呢?这个就涉及到一个返回值的。传、传、参问题的就是你的那个等号的运算符,同在你等号的运算符同在,你是不是我们用的那个是是一个return seeing lis的,然后你的那个返回值类型是Colin是吧?这个等号的运算符同在里面,你你的返回值是return in this,它这个是值传递的,就return返回值返。

返回值值传参复制时调用了拷贝构造函数

返回值是值传递的,所以说它是有值传递,代表什么意思?值传递代表它有复制。 你既然是这个是复制啊,复制是不就是拷贝了,你把值给复制了一遍了,那是不是就是,就是你把这个值返回的这个值里面的东西本身就是一个对象return新粒子吗?粒子指向的是个对象吗?你新粒子的话,那你就是一个对象来了,对象的值在多少,那你复制了一个对象的值,那是不是就意味着你复制啊,就拷贝了,所以你这个对象肯定要被拷贝一份,然后拿去用,是不是?所以他就调用了拷贝构造函数,所以他在这里不单单打印了等号,运算符从载还打印了拷贝构造函数,那个打印信息。

他还打印了拷贝构造函数里面,你写的那一条打印信息,就他不单单打印了等号,运算符从从在里面你写的那条那条打印信息,他还打印了拷贝构造函数里面,你写的那条打印信息,就说明她也用到了拷贝构造函数,这个是跟返回值,它是一个值,就是它返回值,他返回的是一个值,然后这个值你要是一个复制的。他是复制了一份,他重新复制了一份的,他是这个意思,所以他就他的他是直传餐返回值是直传餐,所以他是复制了一份返回值,是复制了一份,所以历新历史,他是把那个对象又重新复制了一份新的,然后给了你,所以他是一个拷他用了,所以他肯定是用了拷贝构造函数的。

引出了返回值中要加入&提高效率

所以说从这里我们也看出来了,就是因为你返回值是直传参的,它是复制了一份的,它是把你这个对象又重新复制了一个新的对象出来,再传出去,这里效率是非常非常低下的。

返回值是变量,复制变量,返回值是对象,调用拷贝构造函数复制

说你无论如何,什么情况下它的返回值都是直传餐呢?你如果返回值返回的是一个普通的变量,那么它就把这个变量复制一份,再返回给你。如果你返回的值是一个对象,比如说新,即使是吧,返回值是个对象,那么他就会把这对象复制一份,再返回给你,那复制一份对象就是考,那你肯定就要动用拷贝构造函数才能复制对象,所以他就是拷贝构造函数用了他复制了。所以返回值本质是值传参本质是复制,所以他效率是非常低下非常低下的。

回归正题:初始化用拷贝构造函数,赋值用等号运算符重载

这个是有一些细节带出来的一些更细的细节,但我们现在主要关注的点是,什么时候用等号运算符存在,什么时候用拷贝运算函数啊,拷贝构造函数,就你如果初始化的时候,他用的就是拷贝构造函数,如果你是赋值的时候,他用的就是等号的运算符,重在总结的,总结之后就是这样子。

##为什么等号运算符重载要加const,其他的运算符重载不用加 他这个运算符存在,你如果是加oppo的,家里面加不加控制的都无所谓,但是你包括你其他的,比如说其他的任何的东西加不加控制的,其实没有所谓你家控制的,只是代表你更好一点,就更细节一点,但是运算符存在里面的等号里里面,你如果不加控制的,它就会报错,为什么呢?这就涉及到它的返回值的关系,因为你一般你用。等号的时候,你一般都是要用它的返回值给它赋值的返回值,它从C语言里面去看,它是放到了一个函数调用堆栈里,然后它的编辑器,它自动会把这个你的返回值变成cost类型的,所以你一旦用了等号,运算符重在。

那么你的这个返回值就要被用到了,这个被用到的返回值呢,它是辑,它会帮你自动把它变成cost类型的,那么你如果用它这个返回值的时候,你不写cost,那就会报错类型不匹配,所以你用,当你用了等号的运算符存在时,里面的参数必须要写成cost。

自赋值

这里还有一个字赋值的概念,就是a等于a,你会发现a等于a,你如果放到他的那个等号运算符存在里面,他是不是就是历史点a啊,历史箭头X等于啊,则点X,历史箭头Y等于的点外,那你传进去的,跟你本身是一样的,A等于a的情况下。那么你就会发现他们两个虽然是两个东西,但是他们共用了一个指针,这个东西是不是跟之前遇到了一个情况很类似,就是拷贝构造函数的时候,当你涉及到指针的时候,当你涉及到箭头的时候,是不是它就会出现一个机构函数?

地址一样,带来与深拷贝时类似的析构时问题

它就会出现一个西勾函数,你前面的勾掉了,后面就没得吸够了,因为你用的是同一个地址,所以这里就涉及到深拷贝跟浅拷贝了,你这里的话,你用到你一旦这么用a等于a,那么你就是普通的拷贝,构造函数是就会出现问题,他必须得用生拷贝,所以这样是不合不合适的。就目前来讲,所以当你你为了,所以你为了避免这种情况,你最好就是在等号运算符存在里面。加一个条件判断,避免他这么用,就说如果他这么用了,你就报错,或者说打印个什么,说不能这么用,就不能a等于a这么用,比如说你打你说一个就加个条件,判断符,比如说你加个条件判断if this不等于and other就说如果他的。

就说,如果它的历史,这个地址不等于它的and other这个地址的时候,你才执行你的等号运算符的存在,否则你就不执行,就说你保证它不要出现a等于a,这种情况,因为你出现a等于a就出现了,那就出现了声拷贝,你这里用的只是普通的浅拷贝,所以是不能用声拷贝所以避免出现这种情况,你就加一个条件判断,不让它出现这种情况。

而且换另一个角度讲,你自赋值a等于a,它是不是就是同一个东西了?那你就没有必要说你的这个等于你的,你就没有必要说再用力使箭头X等于啊,De dian X,历史箭头Y等于点歪了,是不是你不用执行这一步了,所以你条件判断,如果他一旦抢,一旦它相等,你就不用执行这一步,你直接一个return新历史就行了,是不是因为你a是等于a的,你没有必要再一个再复再重新写了,是不是。你直接你你你既然你这么傻,用了那个a等于a本身这就不合适的,两个都是都是一样的是不是,那你就不用执行它等号预算符存在里面东西了,你直接一个在等号预算符里面,把里面的你那些操作全部都都一个条件判断不执行掉,然后后面直接保留一个return新例子,你把一个新例子再返回出去就可以了。因为本身是同一个东西嘛,你返回出来返回你要用的话,你就返回出去就行了,没有必要操作是不是。

解决方法:直接return *this,直接用值

就是说你把里面的操作都条件判断去掉,条件判断不执行,然后直接直接返回出来就行了,因为你a等于a嘛,同一个东西了,所以直接返回出来就行了,所以直接return this就行了。

为什么会看到别人写等号运算符重载时都会写条件判读那,就是为了处理当有人写a=a时的情况

所以你会发现很多写等号运算符存在的都会写上这个条件,判断if this不等于N的other,为什么呢?因为你会因为你写类的人,你是不知道他用类的人,他到底会不会真的会出现这么一个低级的一种写法,A等于a,完全没有必要的一种多余的写法,它一旦这么写了,你没有这么处理,那么它就会出现一个深拷贝的一个问,带来一个深拷贝的问题,所以你为了避免出现这问题,你就,你就提前把这个东西给解决掉,让他当他出现这问题之后,你跳过不执行里面的那个操作,直接返回出来。

返回值中加入&提高效率

那么你要如何避免它的返回值,然后是值船餐,然后它要复制从而降低效率呢?那么你就要把它返回值改成引用,比如说你这里,你其他任何东西都不用改,你也是return,新历史这里也不用改,你唯一要改的是把它的返回值改成那个Korean air e de and加个end附上去就是在函数开头,他不是写了返回值吗?你在那返回值,那里加个end就是corda nary coordinate and coordinate and。

C++引用的发明就是从这个等号运算符重载而来

C加加的引用,就是来自于这个运算符重载里面的那个传参的尴尬,发明出来的就是就饮,就是C加加里面本身那个你运算符重,再比如说那个等号等号的运算符虫在你后面的传参,你按理说应该传指针是吧,那你传指针之后,那你家里有对象吗?你对象不是指针呢,你对象不是指针的话,那么你你下面用的时候,你传参传的是。是指针变量的话,你后面是不是对象,你要要取个星号不,你要不不不不,你对象要取个取个and符取他的地址才行,是不是那你后面肯定要写,肯定不能写C等于a了,那肯定要写C等于na了是吧?因为你要取拿的是and的那个地址,是不是啊,你要拿的是a的那个是吧,你要那a的地址是不是。

但是你这样的话,那你你右边就是a了,你左边是不是应该是and c才对,因为你的数据类型要一样吗?那and c那你C也要去变成end,那就是and and c等于a了是不是?那有些人他可能没有注意到这点,那就写成a等于C了是不是?所以说a等于CAE等于en de re c等于a了是吧?所以C等于AC等于a and c and and a,这三种情况很多人都不一定能搞得清楚是不是?然后加他早期的时候呢,可能就。都允许你这样写,都允许你是对的,因为他怕你写写错嘛,所以他说允许你这三样写都对的,那这样他就尴尬了,那指针是不是概念就混乱了是不是,这不严谨是不是就是很很尴尬是不是?所以这个时候呢,没办法,他就发明了个引用,就引用就从这里出来的,你把传舱你传引用的话,那就可以直接是C等于a给了个新概念,给他。

你给了一个新概念给他,你遗传引用的话,你就可以直接用C等于a了,不用FC等于a了,这个新的概念引用就出来,就这样出来了,那最后变成了从NGC等于a,然后C等于a或C等于直接就变成C等于a最好就可以直接用C等于这样就不尴尬吗?因为你用了这个新的概念吗?不是指针的概念吗?是不是,但是他早期由于也是支持这样子的一个情况了,所以你按的C等于a,还有C等于a都可以,所以这就是一个比较隐晦的一个尴尬的地方。

其实你就算传的是指针,你按着C等于AC等于ACDA也可以啊,C等于a的话,可能不可以,哦好像是可以的,Cdma也是可以的,反正好像用纸船纸的话,这三个也都是可以的,但是就是比较尴尬嘛,不太对是吧,但是他还是可以,所以他必就是为了避免这种尴尬,他最好最好还是引了一个新的概念出来,要引用引用,引用的就不是指针的,那你可以用引用去解释这个现象,那引用的话就可以用直接CD了,从语法上面就不会说很尴尬很很别扭了,你用引用嘛,那就可以直接C了。

Java里面的字符串,它是比较特别,它是固定的,如果你要字符串,你要变大,那你还要重新申请一个字符串,然后把之前的废掉,然后用个新,用新的大的字符串,然后企业家好像是这样子,就是他用一个数组指向那个字符串,然后放在堆里面,这个还不是太清楚,后面看看。

C++默认的析构函数没有delete,所以一旦用了new就要自己手动写析构函数

这里再回顾一下,C够函数啊,西勾函数什么时候该写什么时候不该写。如果你分配的是静态内存,那就不用写析够函数,但是你如果分配的是动态内存,你要申请堆了,你要堆里面的东西,那你必须得要用C够函数,把你的那个堆也是放掉,为什么呢?因为C加加里面的si go函数是默认没有delete的,这是绝对千万十分要注意的,一.c加加里面默认的析构函数是没有delete的,所以你一旦用了动态内存分配,你用了的利特,不是你用了,嗯那你用了那个六,你申请的那个堆,那么你一定要自己手动写析够函数,然后把delete加进去。

数组的delete要加[]

然后还有一点就注意的是,你如果那个你要释放的内存呢?是一个数组,那你就是不能用直接delete了,你要delete中括号,你要用到这个关键字,就它关键字就不是delete了,而是delete中括号。

++a和a++的运算符重载是一个特例,先跳过

这++a跟a++是一个特例,就是他在做运算符重载的时候是个特例,他前面的变成了后面的,后面的变成前面的,这个的话遇到了再说吧,后面当你真正工作时候遇到了,然后再看,再回过头回过头来看。

友元函数

下面说一下友元函数,友元函数的一个初步理解,就是说你的我们目前现阶段接触的函数基本都是写在类里面作为成员方法的,然后你如果要把这个函数放到类的外面去,就是完全的累的外面去,他已经完全不在累的外类的里面了,这个时候呢,这种函数在C里面是否存在呢?其实是存在的,那么你这种函数你到时候要调用时候怎么调用呢?这个时候就涉及到了一个有元函数,你可以把它的这个函数的名字放到那个类里面去,然后在那个函数名字前面加一个friend关键字,就是说你写个friend关键字,然后把那个函数名字写上去,然后还有它里面的括号传参也写进去,然后后面加个分号。

这个时候呢,虽然这个函数它不是本质上不是这个类里面的成员方法,但是它是作为一个有原函数存在,你这个类也是可以使用的,也是可以使用这个函数的,虽然它是在外面的,但是你用个friend关键字,就把它作为一个有元函数就可以使用。

运算符重载的第二种方法:友元函数,不是主次而是平行了

用运算符重载的第二种方法,就是用友元函数去实现,你用友元函数去实现的话,那么你里面传的餐,就是你要把它的类型放进去,就是说你这样子的话,你你一旦这样子的话,你就不是说把其中的一个作为例子,然后把另外一个作为着,然后你这样的话就是没有主次之分了。这样的话就是平行的两个两个运算符,存在你之后的两个要运算的东西,你是放到,你就一起,一起放到那个参数船舱里面去了,两个是平行的关系的,不是主次的关系。

什么时候用第二种友元函数写运算符重载

那么什么时候适合用独立函数,然后类里面再去把它作为一个friend友元函数去做,运算符虫在什么时候适合直接写在类里面,作为运算符虫在呢?这个就涉及到刚刚说的主从跟并列的关系,比如说你如果是C等于a加B的情况,那么你右边的a加B,他们两个应该是一个并列的关系才对,那么这样的话就应该是用独立的函数,然后。再作为一个有元函数,把它放到里面去,为什么呢?因为有原函数这个这个独立的函数,它里面的传参是传两个参的,这两个参之间是相互平等,相互相互并列的,但是你如果是用之前第一种方法,那种运算,写在类里面的运算符存在的话,它是有一个主从关系的,这样的话就不太恰当。

不过,这一些都是一些没有100%说一定要按照这这么做的东西,就是说这个不是一个讨论的焦点,就是你想,其实这个运算符存在本身就不是太有意义的东西,没有必要在这里说宽了,这么死,到时候怎么用就怎么用,也就是说这里不是问题的焦点,也不是一个一定要讨论出一致的结果。

c++并非所有都可以运算符重载

然后C加加里面并非所有的东西都可以做运算符存在,比如说size of啊,然后点那冒号,冒号啊,Sharp,符号这些东西,就是除了这些东西之外,还有一些其他的,就是说,有一些东西在C加加里面是不能做运算符,重在的就是它不支持运算符存在的就有一些。

静态类

什么叫做静态类,就是这个类里面只有静态成员的类,就叫静态类。

c++没有静态类

但是注意一点c加加里面,它是没有静态类这个东西的。

静态成员变量和普通成员变量的区别

区别一:静态成员变量需要在类外面重新定义一次

有关这个静态成员变量,它跟普通成员变量的区别是,你除了在那个类里面定义了一次,你还要在在类外面再定一次,比如说你在类里面已经定义了一个static inter height分号,然后你除了这个之外,你还要再累的外面再定一次inter person冒号,冒号,Height分号,就是说你那个静态成员变量还要再累的,外面再重新定义一次。

区别二:静态成员变量不用创建对象就可以用

静态成员变量和普通成员变量的区别是什么?静态成员变量,你可以不用这个类创建一个对象,然后再用对象去调用,你可以直接用它这个类,然后冒号,冒号,然后去调用,比如说你这里有一个静态成员变量,然后你。

比如说你这里有一个静态成员变量height,那么你在main函数里面你可以直接person,冒号,冒号,Height等于25,分号直接可以这么用,你不用再一个,再用这个person这个类去创建一个对象,你直接用这个类去用它就行了。这个就是静态成员变量,后面的包括静态成员方法也是一样的。

区别三:静态成员变量创建的所有对象都是指向同一个,共享

这里有一个很神奇的事情,就是说你你创建了五六十个对象,然后你这个对象都指向一个成员变量,比如说你创建了P1P2 P3 P4 P5 P6 P7 P8P9,这么多的对象,然后你都指向那个类里面,同一个成员变量height,那么就有问题了。这些指向的是不同的,害特还是相同的害特,它指向的是同一个害。它是共享,包括你的静态成员变量,你直接用类冒号,冒号去用,你没有创建对象,这种情况下它也是共享的,就是说都是共享,指向的都是同一个成员变量height。

由此导致静态成员不能用构造函数初始化,也不能在类里面初始化,智能在类外面

注意我之前说的对象,它所有的都是共享的,这个是针对静态成员来说的,如果你不是静态的话,是不是共享的,所以这也是决定了为什么你的静态成员变量,你不能在构造函数里面,说实话,为什么呢?因为构造函数它是独立的,你你构造了100个对象,这100个对象不是共享的,但是你静态呢。你静态它是可以共享的,所以这跟构造函数是矛盾的,你不能用构造函数的,所以你那个静态静态成员变量,你是不能用构造函数去初始化的,然后你的这个静态成员变量啊,它也不能够在类里面初始化,它必须得在内外面进行初始化。

由此又导致静态成员变量不能用成员初始化列表初始化

所以同样这个静态静态那个成员变量,它也不能用成员参数列表去初始化,为什么呢?因为你这个初始化列表就是在构造函数里面的嘛,你构造函数都不能用来初始化,那你怎么可能用初始化列表呢?

普通成员方法访问静态成员变量

关于普通的成员方法,能否访问类里面的静态成员变量,是可以的,而且有三种方法可以访问,一种是你在普通的成员方法里面用

person::height=333;

第二种是。直接

height=333;

第三种是用this

this->height=333;

,这三种都可以。

但是建议用第一种,为什么呢?因为这种方式,人家一看就知道你用的是静态成员变量,而其他两种别人看不出来,以为是普通的成员变量,所以最好用第一种,让别人一看就知道是静态成员变量。

静态方法不能访问非静态的成员变量和方法

但是呢,在静态的方法中是不能访问非静态的成员变量跟成员方法的,就是在静态的方法中,你只能访问静态的成员变量跟成员方法。

硬要访问只能靠传参,但是已经很间接了

你如果硬要在静态的方法里面去访问非静态的成员变量的话,那么你只能通过传参去实现,就是你在那个成员静态的成员方法的那个船舱的括号里面传入你的那个非静态的成员变量。

然后用你传进来的这个成员变量,在你的静态的成员方法里面去使用。

但是你这个通过传参的方式去访问,这已经是完全是另一个维度了,就是说它已经是非常间接的方式,任何的东西都可以通过传参去访问的,所以其实抛开这个不讲,那么就是这样子,就是说静态的成员方法,就是本身是不能访问非静态的成员变量的。

变量是什么时候被分配地址的?链接时候

所有的变量都是在链接的时候给他分配地址的。

就是说,所有的变量分配给他分配内存分配地址的时候,都是在链接的时候,然后程序在加载的时候就落实到这些内存里面去。

静态成员变量和方法从生命周期角度看等同于全局变量

这个静态成员变量跟静态成员方法,它的它的这个生命周期啊,完全跟全局变量,跟全局函数是一模一样的,完全等同于全局变量跟全局方法,在生命周期这里来看。

换句话说就是通过全局变量的方式实现的

也就是换一句话说,C加加里面的静态成员方法跟静态成员变量,就是通过全局函数跟全局全局变量去实现的。

普通成员变量和方法就比较像局部变量或者用堆申请出来的变量

然后他这个普通的成员变量跟成员方法,它是跟对象绑定的,你每生成,每创建一个对象,就有一个新的普通的成员变量和成员方法,你美迪丽的一个对象之后呢,这个成员普通的成员变量跟成员方法就不在了,这就很像局部变量的那种思想,是不是就很像那种局部变量,你用的话就有新的,不用的话就是迪丽的这样。啊,这个也很像那个mylove申请内存,就是这个也很像,就是堆嘛,就是堆内存,用的时候申请,不用的时候就delete掉,是吧,它跟全局变量就不一样,全局变量是你程序一开始就有要等个程等等等,到整个程序结束才没有是吧,它不是这样子的,它是局部的。

就是说你这个对象,如果是你没有用六根迪利特,你用的是普通的一个,直接加分号那种,那他就很像站里面的嘛,他就是占了他就很像局部变量那种感觉,然后你对象如果是就说你你什么东西很像局部变量的感觉呢,就是说你这对象的绑定的那个普通的成员变量的成员方法吗,很像局部变量的感觉嘛,然后如果你是。那个对象是用六根迪特,然后分配在堆内存上的,那么你的这个对象对应的绑定的那个普通成员变那个方法就很像,就是也是就分配在堆内存上面的那种感觉嘛,其实不是那种感觉是完全就是嘛。

区别四:静态成员在类里面不占内存,简单说就是没有在里面

然后静态成员变量啊,他在这个心你创建的对象里面,是不占存储空间的,就比如说你用这个person有个破损的,这个累吗?你这个类里面有一个静态成员变量,然后叫做害特是吧,然后你现在你新建了一个对象,根据这个person创建一个对象,那么你根据这个person创建了这个对象,他是不是也包含了这个静态成员变量在里面,是吧,但是他这个。它不占内存的,就这个对象里面,它虽然有这个类里面这个静态成员变量,但是它不占内存,它你就你新建那个对象嘛,这对象是占内存的嘛,但是这个对象里面虽然写了静态成员变量,但是它里面的静态成员变量是不占内存的,简单说就是

简单说就是它不占不占内存嘛。

就是形式上好像写上去了,但其实没有分配内存

简单说就是它形式上面写上去了,好像是有的里面实际上他是没有给他分配内存的。

因为本质上它自身早就已经创建了内存了

因为从本质上来说,他这个已经创建了一个内存吗?你,你们因为你这个本质上已经有内存了,他是跟全局变量的逻辑是一样的,当你这个类出现的时候,定义的时候,他的类里面的那个静态成员变量就已经作为全局变量申请内存了,那么你再新建一个对象的时候,他是作为一个局部的吗?局部变量那种那种感觉的吗?他没必要再给你这个全局变量在申请内存了,因为你之前已经申请过了,他没有必要了,所以他是在让你从轻新建一个对象的时候,它里面的那个静态成员,静态成员变量跟静态成员方法,它是不占内存的。

静态成员的用处

静态成员变量的用处

共享计数器

这个静态静态的这个怎么用呢?他今属于就在于这个,比如说你呢,Pad加加,你打开一个窗口,两个窗口,三个窗口,四个窗口,你每打开一个窗口,你要记个数是吧,然后方便,你最后说,如果你你关到最后一个窗口的时候呢,技术变成零,它就自动把整个程序关掉是吧?那你这个技术就应该就应该做成静态类型的静态,静态的一个成员变量要独立出来吗?要共享吗?你每打开一个就加加,每打开一个就加加码,最后技术统计你打开多少个窗口,所以它是共享呢?必须得是共享是吧,所以他静态成员让他用在这里,这是其中一个例子。

即公共的东西,就用静态

简单来说就是处理所有的人的,公共的东西的就用静态共享,比如说你创建一个人的类是吧,,这就这就不是静态的,然后你可能这个人的这个类里面可能还你,还要加上一些其他的成员变量,比如说,是不是你可能也要把这个这个产面加到你这个人的这个类里面去,是吧,但是呢,这个就是共享的了,不是只有你和只有你才有,这个就作为静态。成员变量静态成员方法呢,就是处理这些共有的东西,就是说静态的东西就是共有的,共有的一般就是用的、用的静用的静态的,那么刚刚说的是静态成员变量。

静态成员方法的用处

处理这些共有的东西的时候,就用静态方法

那么静态成员方法是什么呢?静态成员方法用在哪里?静态成员方法就是也是用在处理这些共有的东西的情况下用。

我们平常讲C加加是面向对象和面向过程的结合体,它并不是完全的面向对象,这可怎么解释呢?这也可以,其实也可以从静态成员的也就可以,其实从静态这里可以看出来,因为你这个静态,当你没有创建对象的时候,你也可以用,是吧,就你没有创建对象,你直接用类的那个东西也可以用啊,他根根本没有对象就可以用,这就是违背了面向对象吗?他不是面向对象,所以他C加加就是并不是全部面向对象,就在这里体现了。

这个C加加的,它不是纯面向对象,这里只是其中之一个的一个体现,其他地方也有体现。

这个C加加的,它不是纯面向对象,这里只是其中之一个的一个体现,其他地方也有体现。

静态呀,本质是把全外面的全局封装到了类里面去。

就是说它本质上是全局的,只不过你把这个外面的这个全局,把它封装到类里面去,作为类里面的东西。

这个静态变量跟静态方法,跟类里面的普通面的普通方法,它们是有质的差别的,那是100%完全不一样的,你要写的时候,你要完全认清楚,它们之间是有质的差别的。

这个静态变量跟静态方法,它本质上是其实你本质上是全局的,就是他为了他,那他为什么要写到类里面,它就是为了你能够最后你用的时候,他能够跟这个类关联起来吗,这样才能好用吗?所以他就跟这个根据这个类有关的静态的全局变量,就是根据这个类有关的全局变量,放到这个类里面去,仅此而已。所以他这个跟普通成员变量成员方法是完全是两码事,是有质的差别。这个静态的本质上来说,就是他把全局的给他放到类里面去了,让他好用,嗯,仅此而已,他唯一的跟跟这个普通成员变量,跟成员方法的唯一一个相同点,就是他们都在这个类里面,这是唯一的一个相同点,其他的都不同,其他都是有本质不同的。

关于蜜蜂是什么意思,就当一个类,它是蜜蜂的时候,意思就是说我们不希望它这个类作为父类被人继承。

静态类属于一种密封类

这个静态类就是属于一种密封类。

这个C加加里面的静态成员变量跟静态成员方法,有点像,那个C园里面的静态局部变量,你去仔细品是真的很像的,那静态局部变量的话,他是就他,他是只是限限定于在这个这个局部局部内的嘛,但是他又不希望他的这个东西会会在随着它的生命周期去去死掉吗?那么他就用了个静态局部变量,然后静态静态成员变量跟静态成员方法呢,他也是。他希望这个,希望这个方法或者变量,他在这个类里面的是吧,希望他能够在这个类里面,然后不被其他的用是吧,就只是属于这个类是吧,但是呢,他又不希望这个静态程序变量跟静态程序方法,那么快的就随着他的生命都期死掉,因为他你如果是创立了个对象的话,你对象你如果用完了,那你就滴滴掉吧,那就死掉吧。

但是他如果这个静态成员变量,静态方法,成员方法它属于类的话,那么他就是累的话,他就他就不会随着那个对象的迪丽特尔死掉,他就还是会在的,所以它这个就很像,就很像那个静态局部变量的感觉,就是他也是放放到一个范围里面去,但是它它不会随着正常的那种生命周期,而死掉,他就是还是会在就类似于把它做成全局变量的这种功能,但是还是圈在一个范围里面去,这就很像那个静态局部变量。

上面讲一下静态类,首先你要知道西加加,他本来是本身是没有静态类的,它不支持静态类的,他就说他不直接支持静态类的,就是这样,为什么什么叫做不直接支持啊,就是说他没有静态类的一些功能,比如说你如果是在Java c sharp里面,你如果你把这个静态类说明为啊,你把这类说明为静态类的话,当你做出了一些静态类不允许的事情的时候,他Java c sharp就会报错,编译器阶段就给你报错,但是西加加他不会,你如果把他家家里面你认定这个,你把它设为静态类,那你做了静态类不允许做的事情之后,他编译器不会给你报错,这月的C加加不直接支持静态类,但是你是可以写静态类的。

静态类的话就是它就是直接在那个class前面加个static吗?就作为一个静态类的,静态类里面的话,它是什么叫静态类,就是里面只包含静态成员的类,它不包含其他东西,所有的东西都是静态成员,无非是静态成员变量或者静态成员方法,所有东西都是包含,这个只是招,只是包含这个,那么这也就决定了他不能有相关的构造函数,因为你一旦要构造函数的话,那你的那你是不是就等于可以创建对象了,那就等于是不是静态的。是吧,所以他就决定了,他不能有构造函数,还有一些其他的一些特殊的一些规定,那么这个静态,这这个这些规定的话,因为你没有实际接触过,你也不知道他具体要要做什么,你就这个东西你可以先跳过,不用管。我们现在主要知道静态类,它主要是用来干嘛的,它主要在c shop跟Java里面,它主要是用来写一些纯方法的类。

就说他写一些纯方法的类,这些类的话呢,放的都是所有都是一些方法纯方法,然后呢,我不希望这些这些类呢,是去创建创建对象,他这个方法的话,你就拿来就可以直接用,就是它是个纯方法的类,就是怎么说,就是纯粹就是把所有的方法集中在一起,变成一个类,然后这样的话,它这个静态类的话,它虽然不能继承,但是你可以用它吗。用它的话就是直接用它里面的东西,对静态类它是不能被继承的,所以它也不存在说什么private protected public这些概念,它没必要,因为它不是为了继承而存在的,它就是把你就是把一些纯方法,然后把它放到一个类里面去,就是这样子,然后你那些方法的话,你拿去用。

这种静态类它是不能用来继承的,就说他一般都是用来做一些,就是只有统一一个的一种定律,比如说你说一个物理定律,你不可能有物理定律一,物理定律二,物理定律三,他可能只有一个物理定律,那么你就把这,那他就就不能被继承,你不能在他这个基础上进行拓展是吧,那么这个时候它就是一个物理定律,里面都是一些纯方法,是吧,这个你就很容易理解,拿这个例子一举,它里面实现的这些纯方法,你直接拿这方法来用就行了,你不可能在这基础上做什么扩充,它就是一个物理定律,把一些纯方法,物理定律,还有一些纯变量,纯纯粹就是静态变量的物理的物理定律放到一起,那么这个时候你拿来用就行了,你不用再拿来,他拿来做什么继承什么的。

在这个静态类里面,它是完全面向对象的,然后静态类里面,它是它有一些就是注意事项,首先它不能够继承吗?他是一个密封类,然后他所以他也不能够,没有然后,所以他对于那些所谓的public和protected和private,这些已经没有意义啊。第二点就是它不能含有构造函数,它不能被实例化,所以他也不能含有构造函数啊,这是它的第二点。正因为它没有不能构造函数,所以它进更进一步的什么接口也不行,也不能走任有任何的接口,不能实现任何的接口。然后,但是你要注意一点,第三点,它虽然不能够有构造函数,但是它可以有静态构造函数,静态构造函数是什么意思?就是你可以理解为就是全局变量的那种感觉,就是它,它可以在那个类里面写一个静态构造函数。

然后在那个静态构造函数里面写上你的一些类似于全局变量,类似那种那种的初始化定义,就是你在里面写,然后他就会把他分配到全局变量区,全局区就他可以有一些静态构造函数,这是个很特殊的东西,之前没说过这种,他可以,他可以写静态构造函数,在里面放一些全局性的东西,全局性质的一些初始化的初始化的东西可以放到里面去,这个就是她要注意的几点,然后它的用处的话刚刚已经说过了。

这个静态构造函数,简单说就是你如果没有用这静态构造函数的话,你是不是就是可以把他那些初始化,就像我们之前用的时候,没有静态类的这种概念是,我们是出要初始化的时候,是不是要把他那个声明写到类里面去,然后把他的这个定义写到外面去,是吧?作为一个全局变量吗?就是就是你,你是不是要把那个定义写到外面去啊,初始化写到外面去,写到那个外面去,那你用了静态构造函数的话,你可以把你的这个定义啊。把这些定义呀,然后初始化作为全局变量的一些数,全局区的放到全局数据,需要一些变量啊,放到这个静态构造函数里面去啊。这个就叫静态构造函数,它这个静态类是可以有静态构造函数的,但它不能有普通的构造函数。

这个静态类的出现,本质上是做了一个完全的面向对象,就是他把所有的静态的那个成员变量和成员方法呢,都封装到一个类里面去嘛,形成了一个类是吧,这是一个对于完全面向对象的一个完善整,本质上来讲就是这样子。

C加加它是不能优雅地实现这个静态类的,只有高级一点的语言,Java后期shop,它才能实现这种完全优雅地实现。这种静态类,就比如说你C加加里面,你是没有这种静态

标签: da4y变送器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台