96SEO 2026-02-19 22:04 34
再次理解类和对象这篇文章呢我们来再来对类和对象做一些补充进行一个最后的首尾

那上一篇文章呢我们学了类的6个默认成员函数其中我们第一个学的就是构造函数。
构造函数是一个特殊的成员函数名字与类名相同,创建类类型对象时由编译器自动调用以保证每个数据成员都有
虽然经过上述构造函数的调用之后对象中的成员变量已经有了一个初始值但是不能将其称为对对象中成员变量的初始化构造函数体中的语句只能将其称为赋值。
因为初始化只能初始化一次即在定义的时候赋初值而构造函数体内可以对成员变量进行多次赋值。
是不是没有啊我们构造函数都没写那编译器是会默认生成一个但是我们知道默认生成的根本就不会对内置类型进行处理。
因为const变量必须是在定义的时候赋初值而我们上面说了构造函数里面只是对其赋值并不是初始化。
之前文章里我们在讲解构造函数的时候说了C11不是允许内置类型成员变量在类中声明的时候可以给缺省值嘛。
_b必须初始化即在定义的时候赋初值但是现在是不是没法搞啊构造函数里只能对其赋值并不是初始化。
那我们是不是要给成员变量也找一个定义的位置不然像const这样的成员变量不好处理。
我们可以认为对象定义的时候其成员变量也就定义了但是一个对象可能有多个成员在对象定义的地方也没法给某个成员初始化啊。
那面对上面的问题我们的祖师爷就要去给成员变量找一个定义的地方那最终找来找去呢还是把目标锁定在了构造函数。
以一个冒号开始接着是一个以逗号分隔的数据成员列表每个成员变量后面跟一个放在括号中的初始值或表达式。
每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
我们上面举的例子就是const成员变量它必须在定义的时候赋初值所以必须在初始化列表对其进行初始化定义的时候赋初值当然C11之后可以给缺省值这样如果没有对它进行初始化编译器就会用缺省值去初始化。
因为默认生成的构造函数对内置类型不做处理对自定义类型会去调用它对应的默认构造函数不需要传参的构造函数都是默认构造函数所以如果自定义类型成员没有默认构造函数我们就需要自己去初始化它。
_bb;来说会调用它对应的默认构造类B我们虽然没写构造函数但是有编译器默认生成的构造函数。
尽量使用初始化列表初始化因为不管你是否使用初始化列表成员变量都会在初始化列表定义
成员变量在类中声明次序就是其在初始化列表中的初始化顺序与其在初始化列表中的先后次序无关
构造函数参数a接收传过来的11先初始化_a1然后_a1去初始化_a2所以都是1是吗
原因就是成员变量在类中声明次序就是其在初始化列表中的初始化顺序与其在初始化列表中的先后次序无关
就跟我们之前提到的内置类型之间的隐式类型转换转化是一样的会产生一个临时变量我们再来回顾一下
这里呢也会产生一个临时变量这个临时变量就是用1去构造出来的一个A类型的对象然后再用这个临时对象去拷贝构造我们的a2。
注意拷贝构造也是有初始化列表的因为拷贝构造函数是构造函数的一个重载形式。
1是不是先用1调构造函数创建一个临时变量然后再调拷贝构造构造a2。
那其实呢C编译器针对自定义类型这种产生临时变量的情况会进行优化
编译器看到你这里先拿1构造一个对象然后再去调拷贝构造有点太费事了干脆优化成一步直接拿1去构造我们要创建的对象。
当然不一定所有的编译器都会优化但是一般比较新一点的编译器在这里都会优化。
你凭什么说这里没有优化的话是会产生临时变量的说不定人家本来就是直接去构造了呢
这里产生了临时变量而临时变量具有常性所以我们加了const就行了。
欸那不是说优化了嘛但是这里是引用就没优化了直接拿10去构造一个临时对象然后c就是这个临时对象的引用所以只有一步构造就不用优化了。
就被会销毁而这里引用去引用一个临时变量的话会延长它的声明周期的。
构造函数不仅可以构造与初始化对象对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数是支持隐式类型转换的C98就支持这种语法了。
但是呢我们刚才说的是对于单参数的构造函数是支持这种类型转换的那多参数的构造函数呢
那这里能不能也像上面那样支持隐式类型转换呢两个参数的构造函数那这样去用
那首先要告诉大家C98是不支持多参数的构造函数进行隐式类型转换的。
不过呢C11对这块进行了扩展使得多参数的构造函数也可以进行隐式类型转换但是要这样写
那同样的道理如果我们不想让这里支持这种类型转换对于多参数的构造函数也是在前面加一个explicit关键字
要求我们实现一个类并在程序中能够计算出一共创建了多少个类对象。
直接数是不是有可能不靠谱啊因为有些创造类对象的地方是不是会进行优化这个我们上面刚刚讲过。
大家想一下要创建一个类对象有哪些途径是不是一定是通过构造函数或者拷贝构造搞出来的。
那我们是不是可以考虑利用构造函数和拷贝构造来计算创建出来的对象个数啊。
然后每次调用构造函数或者拷贝构造创建对象时就让n那这样最后n的值是不是就是创建的对象的个数啊。
首先这里我们用了一个全局变量那首先第一个问题就是它可能会发生命名冲突其次全局的话是不是在哪都能访问它而C讲究封装都可以修改它啊如果在其它地方不小心了几次结果是不是就不准了啊。
我们把统计个数的这个变量放到类里面这样它就属于这个类域了就不会命名冲突了然后如果不想让它在类外面被访问到我们可以把它修饰成私有的就行了。
那它是不是就属于对象了但我们要统计程序中创建对象的个数这样我们每次创建一个对象n就会定义一次是不是不行啊。
那这样它就不再属于某个具体对象了而是存储在静态区为所有类对象所共享。
大家可以想一下嘛缺省值其实是在什么时候用的在初始化列表用的用来初始化对象的成员变量的而静态成员变量我们说了它是属于整个类的被所有对象所共享。
规定静态成员变量的初始化一定要在类外定义时不添加static关键字类中只是声明。
这个问题我们之前是不是说过啊不能看到-或者.就认为一定存在解引用还是要根据具体情况进行分析。
在main函数里面我们根本没有创建对象那我们还怎么调用Getn函数呢
难道我们专门在main函数里创建一个对象去调用Getn然后再把结果减1
因为main函数里的对象是我们为了调用函数而创建的对象所以最后要减去。
那我们就可以把Getn函数搞成静态成员函数也是在前面加一个static关键字就行了。
但是静态成员函数有一个特性静态成员函数没有隐藏的this指针不能访问任何非静态成员。
因为非静态成员是属于对象的都是通过this指针去访问的而静态成员函数是没有this指针的。
那它没有this指针就可以不通过对象调用了所以现在我们通过指定类域也可以调用到静态的Getn函数。
13个是不是比之前多了10个啊因为我们又多定义了一个大小为10
这道题呢就是让我们求一个1到n的和但是要求了一大堆不让用这不让用那的。
那不用就不用呗其实借助我们刚才学的知识就可以很巧妙的去解这道题。
我们自己呢定义这样一个类两个静态成员变量_i和_sum分别初始化为01。
然后我们调用一次构造函数就让_sum_i然后_i这样第一次1第二次2…
是不是是需要调用n次构造函数所以我们直接定义一个大小为n的类对象数组就行了。
arr[n];//C99支持变长数组可以用变量指定数组大小但不能初始化。
return
声明为static的类成员称为类的静态成员用static修饰的成员变量称之为静态成员变量用static修饰的成员函数称之为静态成员函数。
静态成员为所有类对象所共享不属于某个具体的对象存放在静态区静态成员变量必须在类外定义定义时不添加static关键字类中只是声明静态成员变量一定要在类外进行初始化类静态成员即可用
来访问静态成员函数没有隐藏的this指针不能访问任何非静态成员静态成员也是类的成员受public、protected、private
我们现在想要那这个类去创建对象那除了我们之前学的方法之外其实我们还可以这样创建对象
匿名对象的特点就是没有名字但是它的声明周期只在创建它的这一行。
我们通过调式可以发现113行执行完这个匿名对象就已经调用了它的析构函数即它的声明周期已经结束了。
现在有一个类Solution里面有一个非静态成员函数Sum_Solution我们知道想要调用类里面的非静态成员函数是需要通过对象去调用的。
匿名对象在这样场景下就很好用当然还有一些其他使用场景这个我们以后遇到了再说。
我们尝试去重载operator然后发现没办法将operator重载成成员函数。
因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。
this指针默认是第一个参数也就是左操作数了。
所以要将operator重载成全局函数。
但又会导致类外没办法访问成员然后我们就使用友元解决了。
operator同理。
友元函数使得定义在类外部的普通函数可以直接访问类的私有和受保护成员该函数不属于任何类但需要在类的内部声明声明时需要加friend关键字。
友元函数可访问类的私有和保护成员但不是类的成员函数友元函数不能用const修饰
const修饰非静态成员函数实际修饰的是this指针而友元函数根本都不是类成员函数所以都没有this指针。
友元函数可以在类里面的任何地方声明不受类访问限定符限制一个函数可以是多个类的友元函数友元函数的调用与普通函数的调用原理相同
};现在有两个类在Date类中有一个成员变量是Time类的对象。
Time类中的成员变量都是私有的那在Date类中我们想访问Time类成员的私有成员变量是不行的。
就是声明日期类为时间类的友元类这样在日期类中就可以直接访问Time类成员中的私有成员变量了。
比如上述Time类和Date类在Time类中声明Date类为其友元类那么可以在Date类中直接访问Time类的私有成员变量但想在Time类中访问Date类中私有的成员变量则不行。
对于类A来说首先有一个整型成员变量然后还有一个成员是类BB里面也有一个整型成员变量。
内部类并不属于外部类它和对应的外部类是相互独立的只是受外部类类域的限制。
对于上面那个类来说我们想拿A中的内部类B去创建对象这样是不行的
刚才类B在A中是Public修饰的所以我们指定类域之后就可以访问了但如果B被private修饰呢
注意内部类可以直接访问外部类中的static成员不需要通过外部类的对象/类名。
在有些拷贝对象的情况下C编译器会做一些优化减少对象的拷贝这个在有些场景下还是非常有用的。
我们说这种场景会发生一个隐式类型转换先拿1去构造一个临时对象然后再拷贝构造给对象a。
我们来分析一下这里正常的逻辑是先拿2去构造一个临时对象然后再去拷贝构造形参a。
当然这几种情况如果我们传的是引用的话那就不用拷贝了所以传参能用引用的话可以尽量传引用。
main函数里面只调用了一下fun2在fun2函数里面先是一个构造然后是一个拷贝构造因为a出函数就销毁了返回的是一个临时变量是a的拷贝这个也是我们前面讲过的知识。
不会的因为这里的构造和拷贝构造并不是一个表达式里的是分开的两步。
当然不同的编译器也可能会不同处理。
返回值返回是一个拷贝构造然后紧接着又把返回值拷贝构造给了aa。
第一种写法呢是构造函数内一个拷贝构造返回值优化之后是这样但是第二种的话是首先main函数内构造一个对象aa2然后函数内一个构造一个拷贝构造最后又赋值给aa2。
刚才我们是先构造一个对象然后返回那如果现在直接返回一个匿名对象呢
那这样的话匿名对象的构造和返回时的拷贝构造是不是就连续了所以这里编译器就会对它进行优化了
计算机并不认识计算机只认识二进制格式的数据。
如果想要让计算机认识现实生活中的实体用户必须通过某种面向对象的语言对实体进行描述然后通过编写程序创建对象后计算机才可以认识。
用户先要对现实中洗衣机实体进行抽象——即在人为思想层面对洗衣机进行认识洗衣机有什么属性有那些功能即对洗衣机进行抽象认知的一个过程经过1之后在人的头脑中已经对洗衣机有了一个清醒的认识只不过此时计算机还不清楚想要让计算机识别人想象中的洗衣机就需要人通过某种面相对象的语言(比如C、Java、Python等)将洗衣机用类来进行描述并输入到计算机中经过2之后在计算机中就有了一个洗衣机类但是洗衣机类只是站在计算机的角度对洗衣机对象进行描述的通过洗衣机类可以实例化出一个个具体的洗衣机对象此时计算机才能知道洗衣机是什么东西。
用户就可以借助计算机中洗衣机对象来模拟现实中的洗衣机实体了。
在类和对象阶段大家一定要体会到类是对某一类实体(对象)来进行描述的描述该对象具有哪些属性哪些方法描述完成后就形成了一种新的自定义类型用然后用该自定义类型就可以实例化具体的对象。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback