首页 > 其他分享 >3. 构造函数

3. 构造函数

时间:2023-06-03 16:56:17浏览次数:28  
标签:虚部 函数 实部 编译器 inline 构造函数

我们继续下去,刚刚谈到设计一个 class,这一页刚刚出现的有这么一页,就是class 呢,首先要有这样的一个声明,你叫它 定义也可以啊,这个不是那么的绝对。然后我就又用了另外一页告诉各位说,其实可以把里面的实部虚部抽出来,这就是一个模板的概念,但这只是先给大家带一下概念,后面我仍然不会去讲模板,我又要再一次回到,就是我们没有模板的情况。

在这张投影片里面出现,告诉各位说,有一些函数在此,就这一个叫做 body, class的本体里面直接定义,但是你也可以不在这里定义,你把它全部放在这里定义,ok! 比如说这里面现在有三个函数,这里有三个函数,这两个函数就是有一个大括号,这样就直接在这里定义了。那上边这个函数呢它没有大括号,它这边分号结束了,所以这是一个声明而已,它并不是在这里定义的,就是这句话的意思。

好我们继续往下啊,这是模板的部分。

inline(内联)函数

接下来我要继续开始讲,我们就一个一个的讲 body 的小部分,首先谈到一个 inline 的概念。什么样的情况会产生 inline 呢,你的 class 你的函数在你的 class 的本体里面,这样定义它就形成了一种 inline ,如果在外头定义它就不是 inline 。那到底什么是 inline 函数,我们享受什么好处,inline 像 宏(micro)一样,不是完全一样,但是有它的特性,而没有 宏 的缺点,那它的特性跟它的缺点,我们就是属于 C 的部分,我们就不去谈了。总之就是,如果你的函数是个inline function 会很好,会比较快也比较好。那么当然我们想说,那所有的函数我都把它写成inline方形,那就最好了,的确是。但是有些方选,即使你说它是 inline。 编译器也不把它做成 inline,编译器 没有能力把它做成 inline 。这个分界点在哪里呢,简单的这样想,就是如果你的函数太复杂,就没有办法 inline, 它对我们写程序的人来讲呢,这个有点讨厌,干脆我们全部都让它 inline 好了,可以。但是你的 inline 只是对编译器的一个建议而已啊,是不是真的变成inline,由编译器去决定。现在再回到这个话题来,所以像这两个函数,它在 body 本体内定义它就是 inline function,那它是不是最后真的变成 inline function,不知道。但这个地方我们看这两个函数是如此的简单,想必编译器有能力把它变成 inline 。那上面这一个函数在这里没有定义,它是在本体的外头,等一下才会看到的,等一下你会看到我也把它写了 inline,有一个关键字啊,会出现在什么地方,等一下你就会看到,那就是告诉编译器说你尽量把我 inline,但最后结果仍然由编译器来决定啊,这是 inline function。对这里有一个,比如说我看看这个 imag,这就是后面会出现的一个一段代码,好我来看一下这个是什么事情,现在先不要管它做什么事情,可是后面出现的就不再本体内定义的,我们可以加 inline。

access level (访问级别)

这个是 inline 的部分,我们看下一页。在一个本体之中很重要的,可以区分为某几大段。用什么样的关键词来区分呢? public 和 private 这个字眼的意思是公开的,被外界所看得到,这个 private 的意思是只有我 class 里面才可以拥有,才可以看得到。那什么东西应该放在 private 呢? 当然是数据的部分,因为我们希望数据是封装起来,不要被外界任意看到啊,应该只有自己人才看得到,所以各位可以看到 data的部分呢 放为private。那函数的部分呢,函数也可以分两种,一种是要给外界用的,一种是我自己只是我处理私人的事情要做的,那在这个例子里面,大部分的函数都是要被外界使用,可以说全部了,不是说大部分,所以所有的函数都放在public里头。这样我们用这种特殊的语法,后面有个冒号来区分为两大块。其实有第三种叫做 protect 保护的,那在我们的例子里面不会出现,我暂时不说它。这些段落是是可以任意的出现啊,也可以交错,我的意思是,如果你这个 body 本体很大的话,你可以先写一段是public啊,然后你想到了什么事情呢,写一段private到后面再写一段 public 都可以,并不是非得要集中成两段,不是这样。好像现在这样子安排,我们来看看下面使用它,有一个是错误的情况,有一个是正确的情况。我们先看看这个,现在这个代码是要创建一个对象,创建对象会调用起它的构造函数。构造函数还没解释,等一下会讲。然后通过对象调用某一个函数,左跟右有什么差别呢,我都想打印出它的实部和虚部出来看,右边是我通过这两个函数来得到实部和虚部,这两个函数就出现在这里,其实里面的动作很简单,就是把实部传出来,跟把虚部传出来,我得到实部,虚部打印出来,这个没问题,因为这些函数是 public。像左边这样呢就不行,我是通过这个对象,我在上一行做了一个对象出来,创建一个对象出来,我直接要去拿它的 data, re 和 im 是这个实部虚部,它是它里面的值,这是 private,所以像这样就是要去取它的 data,这是不允许的。这样我们就说把这个数据呢很好地包起来了,数据一定要通过它的兄弟,它们自己人这些函数来传递出去,或者被设定一个读一个写,不能够直接像这样外部呢就去拿,不可以,除非这些数据它就是public。但我们就是要避免这个事情,好我们把这些关键词 public private,以及它们所形成的这个区域,这种我们叫做 access level 访问的级别,到底谁能够来访问它们呢,这叫访问级别。那在这边就告诉大家哈,你所有的数据都应该放在 private,你的函数如果是打算被外界来呼调用的,那就要放为 public,但是如果你写了一些函数,我只是内部要做一些处理,没有打算被外界调用,你那些函数可以放在 private 里头,私有的里头。嗯好,这章谈的是访问级别。

constructor (ctor, 构造函数)

好我们看下一页,下一页是一个大主题:构造函数。C++ 这个语言说,如果你想要创建一个对象,一个东西,对象就是东西,你想要创建一个对象的话呢,有一个函数会自动被调用起来,不需要你调用啊,它自动就起来了,这个叫做构造函数。比如说我们现在下面这样子,这三行都是要创建对象,第一行的意思是我要创建一个叫 c1 的对象,它的值是实部为二,虚部为一; 第二种的意思是我创建一个对象,它没有没有参数,那应该就是以数学来讲,你可以你可能会想象,那就是 0+0i,i 是虚部,你可能会这样想; 那第三种方法呢,就是用动态的方式去创建了一个复数,得到的会是一个指针。好,这三个都在创建对象,创建对象一定有一个函数会被调用起来。这种构造函数的写法很独特,它的函数名称一定要跟类的名称相同,才能够叫做构造函数,这是第一点。第二点它可以拥有参数,你就去设计吧,看我这一种东西,这个叫复数嘛,那它它的参数应该有几个,我们当然自然想到有实部,虚部这两个参数。第三我们在这个例子里面学习到,这参数是可以有默认值的写法,就像这样,default argument 叫默认实参,可以这么写,那默认的意思就是如果你使用的时候,你在创建的时候没有指明,那就用默认值。如果你有指明,那当然就用你的。所以第一行创建出来就是实部为二,虚部为一;第二行呢创建的时候也是在用这个创构造函数,那就是实部为零,因为默认是零嘛,虚部也为零,因为虚部默认也是零。参数的实参的默认值,是不是只有构造函数才能拥有这种特性呢,不是,其它的函数也可以写出默认值出来。好这个构造函数还有什么特性没有,一般的函数在大家从 C 这边过来,一般的函数就是函数的写法,那这个构造函数比较特别。刚刚我们已经讲过了,名称有点不特别,还有一个呢它没有返回类型,你看这就是一般的函数,它们一定要有返回类型,但是它没有,不需要有。为什么,因为构造函数就是要来创建对象,对象是什么,就是这种东西,现在这个构造函数在这个类里头,所以它就是要来创建这种东西是不能改变的,所以C++ 说,但你不必写,你写的还怕你写错,所以没有 return type。

好这是构造函数的语法,那至于里头要做什么,就由你来设计了,我们应该把收到的参数,设到我们的实部和虚部里面来,所以你可能会看到很多人在这个函数里头,开始写哦,我收到一个实部叫 r,一个虚部叫 i,我就把 r 放到实部里头,把 i 放到虚部里头,它可能会在大括号里面这样写,用 assign 赋值的动作写进去,这样当然是 ok。但是我们要培养一个大气的,正规的好的写法是什么呢,不要这样写。我们应该利用构造函数有一个很特别的一种语法,只有构造函数才拥有,才享有其它其它种函数是没有的,那就是中间这一行,这种语法这种这一行叫做initialization list,还可以翻译成 初值列,因为它设初值,或者叫初始化,做初始化动作的一行。当然我这边是分成三行了,你其实把它弄成完整的一行都无所谓,C++ 跟 c 语言一样啊,它都是一种 free form 自由形式的写法,你随时要在哪个地方断行都是无所谓的。好现在回到这边,这种特殊的构造函数才享有的写法是什么呢,这个的意思也就是,把 r 设到 r 设到绿色的实部去,把 i 设到绿色的虚部里头去,其实和你在后面函数的本体里面,大括号里面去做是一样的意义。但是为什么要在这里做呢,其实我常常判断学生你写的东西够不够,够不够大气,我会看好几点。其中的一点就是,你会不会充分运用这种特殊写法,而不要把它说省略了这一行,把它写到这个函数里面去,那个就是最后结果是一样的,但是那个写法表示你没受过良好训练。这两者的差别在哪里呢,现在先简单讲一下,后也它背后还有很多原理。但是简单的讲就是一个变量,一个东西,它的数值的设定有两阶段,一个是初始化,一个是后面再赋值,assign赋值,它有两阶段,第一阶段就是这里,所以这个才叫做初始化,初直列第二阶段就是在大括号里头去赋值,指定数值进去,你如果不在这里做,你到里头是后面才来做,就等于说你你放弃了那个初始化的阶段,虽然最后你还是把值放进去了,时间点已经晚了一些,效率也差了一些啊。所以虽然结论相同,可是过程是不一样的。那么你可以在初始化这一列,它的语法各位看的很清楚了,就前面要有一个冒号,那至于冒号后面能做哪些事情呢,后面有比较复杂的例子,我们再来说。最常看到的就是在这边设值,给它设初值,或者说把它初始化,这是这种特殊的语法。那赋值就我刚刚说很多人没有去注意到这一点,它们可能会写成什么样呢,就是这样子啊,写成上面这样子,不写三行了,写成这两行,这就是在大括号里面去做复制和三个动作,我这边问大家,这样可以吗,可以吗,我说可以,但是效率上比较差。好这个是构造函数啊,你不可能在你的程序里面去直接调用构造函数,不可能,没有这种语法,你只是要创建对象。而创建对象,下面这些是一些例子啊,那这个函数自然而然就会被调用起来,这是构造函数。对应的,它也有一个析构函数,语法也蛮特别的,但是在我们这个例子里面不需要写析构函数。前面我提到 class 有一个经典的分类,一种是带着指针的,一种是不带指针的,这种就是不带指针的,不带指针的 类 呢多半也不能说全部啊,多半不用写析构函数,像现在这个例子就不用写。那我们到后头来,等到进入第二个例子字符串,我们再来细谈析构函数。

ctor (构造函数) 可以有很多个 – overloading (重载)

构造函数可以有很多个,现现实生活中常常会出现这样吗,常常会。比如说你你现在设计一个一个类,等待着外界要来创建一个对象,创建对象的时候要怎么创建,你可能有很多种想法,你有三种想法,你是设计者吗,三种想法你就写出三个构造函数。在过去的 c 语言 里面,是不允许同一个函数有三个跑出来,不允许。C++ 是允许的。相同函数名称一个以上,这个叫做 overload,重载,那么在构造函数里面的大部分的人啊,大部分的例子,就你很可能会看到一个以上的构造函数,原因就是我刚说的东西要被初始化,要被创建,可能有很多种初值的设定。好在这张投影片里面我准备了两组东西哦,两个1 2,1 2为一组。我们先看这一组,本来呢这里面已经有一个函数的,叫做real,看它的动作是要取得实部,我可不可以现在在写另外一个函数,也叫做 real,它的动作我是打算设定设定实部,刚刚那一个是取得实部,现在这个是设定实部,我都叫做real,可以吗,这边说函数可以重载,所以可以。你可以把这个函数加上去,那这边呢把这个 const 划掉,我从刚刚到现在都没有去解释 const 是什么,我现在也不解释,但是这个函数呢必须把不能有 const ,如果你要加这个函数的话,const 后面再来说。那我们一定很好奇,为什么同名的函数可以有一个以上,既然同样的名称呢,将来调用的时候调用到谁呢,这里告诉你,如果你写了上面这个函数,又写下面这个函数,其实这个函数的名称不是你写的叫 real,不只是这样,编译器是把它变成类似这一种样子,这当然是不是我们人在看的啊,是给机器看的。它会把函数的名称,函数里面的参数有几个,以及这些参数是什么类型,通通都编码编成一个这样很奇怪的东西,只有编译器看得懂。所以我们以为这两个函数名称,这里 一 和 二 是相同,其实是不同的,所以的确,不会有一,不会有两个完全名称相同的函数,是不可以同时存在的,而这两个它名称并不相同,虽然我们以为都叫 real 啊,其实它们真正并不叫 real 啊,这个概念就叫做函数的重载。

那我们再回到上面来,刚刚说构造函数就常常会发生函数重载,就会写好几个构造函数。 那我想那这样子我来写一个这种好不好,第二个这是我新加上去的,那我问说可不可以呢。我们来试看看这个既然刚刚说可以同时存在好,我的第一个版本是有两个参数的,我现在第二个版本是没有参数的,那它们就应该动可以存在了,不管我后面要做什么哈,在语言上呢应该接受这样的同名,但是实际上却不行。这又为什么呢,因为这一个函数有默认参数,我们来看看这一段,如果我现在这两个这两个都是要创建复数,意思是一样的啊,第一行的意思是我要创建一个 c1,我没有给参数,第二行的意思是我要创建一个 c2,我也没有给参数,写法不同意思相同,那我都没有给参数编译器,就来看看我到底可以调用一还是二呢,它看到二这里没参数,所以它是候选人,它可以被调用,但是一虽然有参数,可是它有默认值,所以感觉也可以调用,好你使用的人说我不在乎实部,虚部,你就自己给我吧,所以编译器一看它也可以调用一,它也可以调用二,那编译器也犯傻了,它也不知道该调用谁了,所以在这种情况之下,它就不允许二再写一个,再写一个,二不允许就这两个是不能同时存在。所以我再强调一次,有函数重载在 C++ 里面,同名的函数可以同时存在,其实它不同名,在编辑器看来。第二件事情,函数重载常常发生在构造函数身上。第三件事情,由于目前拥有了这个构造函数已经有默认值了,你还是可以去重载写出其它的构造函数,但是如果你写成我现在给的这个例子,这样两者一跟二是冲突的,这个不行,你可以继续去写其它的构造函数,但是这个不行。这是我们在,开始写一个类的时候,它第一个要碰到的比较大的的问题,就是怎么好好的去写一个构造函数

总结

inline(内联)函数

  • 函数在 body 本体内定义就是 inline function,在 body 外定义 可以加关键字 inline 变为 内联函数,真正是不是 由编译器决定。一般简单的函数编译器会把它变成 inline。

access level (访问级别)

  • public:放一些函数打算被外界(类外)来调用
  • private:不需要外界调用的函数、数据
  • protect:

constructor (ctor, 构造函数)

创建一个对象,有一个函数会自动被调用起来,叫做构造函数。不可能在你的程序里面去直接调用构造函数。

  • 函数名称跟类的名称相同
  • 没有返回类型
  • 可以由参数,可以有 默认参数
  • 一定要使用 initialization list(构造函数独有) 来初始化 data,而不是在 函数内部 通过赋值完成,否则降低效率
  • 不带指针的 类 多半不用写析构函数

ctor (构造函数) 可以有很多个 – overloading (重载)

  • 构造函数可以有很多个,常常重载
  • 函数重载在 C++ 里面,同名的函数可以同时存在,在编辑器看来其实它不同名,编译器会编码为唯一的名字
  • 构造函数有默认值时,需要防止冲突,创建对象时候不知道调哪一个。

标签:虚部,函数,实部,编译器,inline,构造函数
From: https://www.cnblogs.com/odesey/p/17454201.html

相关文章

  • C++逆向分析——构造函数和析构函数
    构造函数与析构函数构造函数structStudent{inta;intb;Student(){printf("Look.");}voidInit(inta,intb){this->a=a;this->b=b;}};如上代码中,我们发现了存在一个函数,这个函数没有返回类型并且与结构体名称一样,那这段函数在什么时候执......
  • 通过定义私有构造函数限制类的实例化
    当在一个类中定义了私有构造函数时,它将限制其他代码在类外部直接实例化该类的对象。这意味着除了类内部的代码,其他代码无法通过调用类的构造函数来创建类的实例。通过定义私有构造函数,可以实现以下几个方面的控制:防止类被意外地实例化:私有构造函数可以确保类的实例化只能在类......
  • uobject只有可以声明无参构造函数和不写构造函数
    (一)结论:(二)测试过程:第一种:不声明任何构造函数:第二种:声明默认构造函数:第三种:声明其他构造函数:(直接报错,需要声明默认构造)(三)ue实现原理:UHT里可以解析出你是否定义了构造函数,是哪种构造函数:参数是否匹配“FObjectInitializer”:不同构造函数,对应使用不同的宏定义: 链接:ht......
  • 编译器绕过拷贝构造函数和返回值优化
    写在前面:在拷贝初始化(也就是用等号初始化,注意使用拷贝构造函数创建一个新的对象不属于拷贝初始化)过程中,编译器可以(但不是必须)跳过拷贝构造函数或者移动构造函数,直接创建对象。1stringnull_book="999";2//可以改写为3stringnull_book("999");这里面”999“隐式的转换为......
  • 结构体就算不用构造函数也可以初始化
    标题结构体就算不用构造函数也可以初始化#include<iostream>#include<vector>#include<algorithm>#include<string>#include<queue>#include<set>usingnamespacestd;structstateAndLevel{ stringstr; intlevel;};queue<stateAndLevel>......
  • 委托构造函数
    一.当构造受委托的构造函数时,受委托的构造函数函数体会执行而委托构造函数函数体不会执行;classPerson{public:Person(){cout<<"这是一个无参构造"<<endl;}Person(constPerson&p){cout<<"这是一个拷贝构造"<<endl;......
  • js原型prototype(实例构造函数的属性) __proto__(实例对象的属性) constructor(实例
    functionPerson(name,age){this.name=namethis.age=age}Person.prototype.sayHi=function(){//原型是公共方法解决构造函数new对象公共属性和方法的内存浪费console.log(this.name+'sayhi!!')}constp1=newPerson('aa',12)constp2=new......
  • 什么是构造函数?它有什么作用?
    构造函数是一个特殊的方法,它用于创建对象时初始化对象的实例变量。每个类都至少有一个构造函数,如果没有定义,则会有一个默认的无参构造函数。构造函数与类名相同,没有返回类型。构造函数可以用于为对象分配内存,初始化对象的状态,执行其他初始化任务等。......
  • 构造函数的调用时机/次数
    一个变量只能调用一次构造函数,那就是在定义变量的时候调用,除非变量为局部变量,否则不会重复调用,一直到程序结束也就调用那么一次。也就是说只有在定义新的变量的时候才会调用构造函数。【eg1】定义在主函数的情况•#include<iostream>#include<windows......
  • c++ 子类与父类的构造函数继承关系
    规范上,子类构造函数肯定是会调父类的构造函数。 如果代码中没写,就会隐含调用父类的默认构造函数(即那个无参构造函数)。如果父类没有,编译报错。 1,展示了当子类要调用父类中带参数的构造函数时:#include<iostream>#include<cstdio>classA{public:A(){printf("......