范磊C++ 原创笔记 第六章 面向对象

来源:互联网 发布:温职院网络课程 编辑:程序博客网 时间:2024/04/26 15:20
 第六章 面向对象
 
 
 
什么是类

类名与结构体相似:

类与结构体相似,都是混合型数据组成一个整体。都是要先定义数据类型。这个数据类型的名称有一半也是自己定义的。

 

 

声明一个类的形式

class human

{

public :

 

private:

 

};

 

human是自定义的名称,但他不是变量名,而是数据类型。

声明完数据类型,才能定义具体的对象名。

 

注:public private可以不写,不写的话所有数据默认属于private。但构造函数不管怎样一律属于公有,默认也是公有。特意写在private里面会报错。

 

注:

 

一、声明一个类,其中变量成员不能具体赋予数值初始化,这样会报错。要初始化赋值要先创建对象,通过对象来初始化赋给具体的值。

 

二、类中成员函数中的变量,可以被直接初始化赋值

 

三、虽然成员变量在类里不能被直接赋值为具体数据,但可以有赋值关系式 ,如: int a = b;  a = b+ 1;

 

类成员函数的内外部定义

 

内部就是在类后面的括号里定义。而外部就是在类括号外面定义。我们可以在内部先声明一个成员函数,然后再在外部定义,也可以在内部声明并定义。

 

在内部定义的话,那就是一般的定义函数的写法。

Class A

{

Void chengyuan ()

{

int a = 33;

 

int b = a;

}

 

};

 

 

而外部,则需要

void A :: chengyuan ()

{

int a = 33;

 

int b = a;

};

 

其中A是类名。类名后面加两个冒号。(至于后面谈到内联函数时,会再谈到函数声明与函数定义的形式)

 

注意:函数定义时,返回值类型,跟参数都需要再写。没有为什么,就算声明的时候已经写了,定义的时候还是要再写。

 

 

 

如何定义一个对象:

 

如: human jack;

 

这个jack就是对象名。他是class human类型

 

human是之前已经声明的类名,jack是自己取的对象名。这个时候这样写已经是定义而不是声明,运行时会给对象里面的各种变量分配空间。

(这里的声明与定义的概念很复杂,之后会讲)

 

如何一次性定义多个对象:定义数组对象

 

如: human jack[ 10 ];

 

这表示创建了jack [ 0 ]~~~jack [ 9 ]的10个对象,在内存空间中连续存放。

 

 

类中的public  private到底是什么?有什么用?

 

跟C语言结构体相比,类多了public 跟private 。重点在于private 。 凡是private里面的成员,想要访问他们,调用他们,必须通过public成员。

其他形式调用不了。

 

C语言的结构体里面的数据,就好比是公用图书馆,这个图书馆只有一楼,所有书都放在一楼。

 

类中private,好比是公用图书馆改进了,变成了两层楼。想进二楼看图书,你必须要先进一楼,没有其他办法。

 

一楼相当于public , 不管你怎么来的,你可以打的过来,你可以散步过来,你可以公交过来。

 

但要进二楼的人,必须是通过一楼那几个梯子。你必须是先到一楼,必须是要上一楼的梯子,这是你上来的条件。

 

 

 

也就是说,类对数据进行了分类,public里面的数据谁都能访问,调用。但private 的数据只能通过调用public成员,public成员再调用private这样子来间接调用。

 

而且往往调用的是那些public成员函数,因为这些函数里面含有访问private的代码。如:

 

public :

 

int func (int a)

{

int a = b;

 

};

 

其中b 是private成员。那么调用func函数,就间接访问了private成员。至于为什么要有公有私有成员,这是为了方便,为了隐私,有些数据时需要权限来访问的。这也是为了数据的安全性考虑,增加安全性。具体初学也难以给予复杂的实际例子说明,具体不用深入研究。

 

就是说,private里面的数据,读取或者修改,只能由public发出命令才行。如果用户直接命令修改数据,读取数据,是不行的。同时,private也只能把数据发给public接受。public一面链接着用户,一面链接着private。private不与用户直接连通,必须要以public为桥梁。

 

private的默认性:

前面说过,如果用户不写public  private  而直接写类的内容,那么内容全部属于private (其中,构造函数,析构函数,复制构造函数等除外,之后会讲到)

 

调用访问对象成员的形式:
 
human.weight();
 
human.high;
 
类名.成员名; 跟C语言结构体成员一样的调用方式。
 
 

 

 

什么是内联函数?内联函数的声明:

 

内联函数就是在函数声明那里加一个关键词inline 。

 

我们在调用函数时,是跳回到上面函数的定义部分进行执行,这样的话有一个跳转的步骤,如果程序调用的多了,那么程序速度会变慢,所以,我们加上inline后,编译时直接把调用部分替换成函数定义部分,也就是把函数定义部分在此地给复制一份。这样运行时,就不用跳转了。直接在当地执行。

 

但复制缺点就是会增加程序的体积。  成员函数的内联跟普通函数内联表达上一致,就不多说了。

 

内联函数声明举例: inline int func (int);  其中参数只有Int 表示接受的是int类型,具体参数名在定义时函数头给出。

 

函数声明与定义的注意:

函数的声明包含附加关键词(如linline), 函数返回类型,函数名,跟参数或者只有参数类型。

 

函数定义如果跟声明分开,那么定义的函数头部分必须要有函数返回类型,函数名,参数类型参数名 ,哪怕声明时已经写过了,定义时还要再写。而附加关键词可以不写(如linline, 声明时如需要一定要写,定义时不用写。)

 

const 用法:五个const的含义:

void p(int x ,int y) const
{
i = x;
};

注意:const在大括号前面,表示大括号里面的成员数据不可以修改,不可以被赋值。这个位置使用const,这个函数必须是成员函数。普通函数不能在这个位置用const . 这里企图对x成员数据进行赋值,会报错。

百度上说应该多用const 。自己想了一下觉得也有道理,因为真正的程序代码很多很复杂,也许一个代码变动就不经意间修改了你不想修改的数据。而const可以作为一个把关,就好比是一个免疫机制,出现不正常了,立刻报错!

普通函数四个const 含义: 

const A * const  func   (const A * const one)

 

/*1*/和/*2*/修饰返回值

  • /*1*/限定返回值(类型是指针)指向的对象的值不可修改

  • /*2*/限定返回值指向的是哪个对象不可修改

/*3*/和/*4*/修饰函数的唯一一个参数,即one

  • /*3*/限定one指向的对象的值(在函数内)不可修改

  • /*4*/限定one指向的是哪个对象(在函数内)不可修改

const在 * 左边是表示不能改变指针指向的对象的值,在 * 右边是表示不能改变指针指向的内存地址。规定就是这样……所以说总是写成double const pi=3.1415926;这样始终放在被修饰的类型后面才是好习惯……

  

 初步构造函数介绍:

 

一、默认构造函数的存在

 

默认构造函数,就是隐藏的函数,它存在于类的public 中,每一个类都会有(只要我们不重新定义不覆盖,之后会讲)

 

human ()

{

 

};

 

这个就是默认构造函数。它看不到,是隐身的。它的函数名就是类名。默认的构造函数没有参数,没有内容。

 

 

二、构造函数的意义与自定义构造函数

 

当我们创建对象,就会先自动调用构造函数,这是内部的设定,就是这样。至于为什么这样,我想是因为方便初始化,把需要初始化的内容定义在构造函数里面,然后一传关键的参数,一调用,马上就给出想要的变量结果。

 

调用完构造函数,对象就创建好了。可以说,构造函数用于构造对象。

 

如果是默认构造函数,那么这个构造函数什么都不做,而前面所学规定,类的成员变量不能在类中直接被初始化,所以如果我们创建对象,调用默认构造函数,那么对象里面的变量大部分是垃圾值。

 

如果我们想创建对象后就自动填上值而非手动一个个赋值,那该怎么办呢?————那就自定义构造函数。

 

 

如:

 

 human (int a,  int b)

{

int a = weight;

 

int b = high;

 

}

 

 

之前我们创建对象,是 human jack ; 那是针对默认构造函数。因为它没参数。而现在参数变成两个了。所以创建对象的时候,要变成 human jack(80,180);  ————这个式子之后再详细讲

 

也就是说,要创建对象,必须先调用构造函数,那么必须要传与构造函数对应的参数才行。

 

而此时默认构造函数已经消失,因为有了自定义构造函数,就会自动覆盖默认构造函数。

 

前面说,默认构造函数是隐身的,如果我们把他写出来,然后再写一个自定义构造函数,那么一样是覆盖,默认构造函数消失。

 

构造函数不能有返回值。关于构造函数还有很多内容,因为范磊这里只是稍稍提了一下,所以放到后面讲。

 

 

什么是析构函数,析构函数的作用:

 

析构函数跟构造函数一样,平时也是以默认析构函数存在,处于隐身状态。

 

它的形式为:

 

~human ()

{

 

 

}

 

就是比默认构造函数前面多了一个  ~

 

构造函数,在创建对象时会自动调用。析构函数,在作用域结束时,会释放作用域里的变量,当释放对象时,就自动调用析构函数来释放对象。

 

构造函数可以自定义,按照我们的方式来构造对象。析构函数也能自定义,但它只有自己的方式来析构对象。

我们可以在析构中加上一些其他内容比如cout 等。

 

自定义析构函数也会覆盖默认析构函数————但我觉得,它还是有析构的功能,这个问题问百度知道,无果。

 

构造函数不能有返回值,可以自定义参数,自定义内容。但析构函数不能有返回值也不能有参数,只能自定义内容。

 

对象数组的析构顺序:

 

当有多个对象被创建,析构时,是从最后被创建的最先开始析构。

 

 

 

 

 

 

 

 

 

 

 

自己的研究:

 

构造函数,是用来构造对象。

 

 

这句话我觉得表达上似乎不太好,(我是菜鸟,我在百度上问了很多人,纠结了很久很久),以为对象是靠构造函数构造的。

 

一个变量,无非是被分配内存跟初始化。被分配内存后,里面就已经有值了——垃圾值——垃圾值也是值。

而初始化,不过是覆盖垃圾值,只是一小小步骤而已。

 

构造函数,只是用来初始化此函数里面涉及到的一些成员变量(这些变量属于对象里的内容),但在这之前,成员变量的内存空间分配不是由构造函数来完成。

 

谁给对象分配了内存,谁才是构造了这个对象。构造函数只是往变量对应的内存里面填一些具体的数据而已,而且它也不一定是把所有成员变量都填上数据,有些可能还是保持垃圾值。构造函数,谈何能构造对象?

 

 

比如 class A

{

public :

 

int f ;

 

A (int a ,int b)

{

a = c;

b = d;

}

 

private:

 

int c;

int d;

 

}

 

然后我们 A a (1,2);   我们构造的对象中,是否有int f 这个变量呢? 答案是有的,但我们通过构造函数来构造对象啊,构造函数跟int f 扯不上关系,怎么对象中会有int f 呢?

 

构造函数,这构造对象的过程中,只是扮演一个小角色。

 

 

 书上说,类不能被赋值。

 

原因是类是抽象名词,而不是具体某个个体,正如我们无法对int 这个类型进行赋值一样——————以上是范磊63页说的,但经过我的钻牛角尖后,觉得这样解释不太好。

 

 

疑点一:类里面的变量都不能被直接赋值吗?

 

百度答案:否。成员变量不能被赋值,但成员函数里面的变量可以直接初始化。

 

我疑问:既然成员函数的变量可以直接初始化,为何成员变量不行?

 

 

百度答案,百度贴吧答案:&*&%¥¥这个答案非常的复杂,饶到底层去了,讲了一大推天书语言,完全不懂。不过最后略微看懂了一点,那就是只有类,没有对象的时候,编译时还是会对类进行编译,还是会有类的信息。

 

 

自己的理解:我们创建对象时,怎样创建?天上掉下个对象?它如何创建,是根据类。也就是说,编译时对类里面的信息都进行了保存,类告诉程序,该怎样初始化对象。

 

我们不能对int 赋值,那是因为int 是完全的规定死了,没有一点可变性。但是作为数据类型的类,也是这样吗?

 

它凭什么不能被赋值?我声明一个人类,我规定人类都是有两只脚,不管是jack还是jim, 这样有问题么?

 

初始化碍着类什么事了?类是数据类型,int 其实也有初始化,它规定Int占用4字节难道不是一种初始化么?

 

我们不能对int 赋值,那么我们是无法对 human赋值,但我们怎么不能对human中涉及的变量来直接赋值呢?

 

所以说,类中不能直接初始化成员变量,我经过2天的痛苦研究求教,认为那只是规定,跟类是数据类型什么的没啥关系。

 

 

 

 

 

一、编译与运行的内存关系
 
编译并不对变量分配内存,运行才会对变量分配内存。编译,只是把代码转换为二进制代码,再加上为这些变量分配内存的代码等其他代码。
 
 
二、什么分配,什么不分配
 
只有实际运行到的代码,才会被执行,才会分配内存。而没有执行到的代码,比如有一个副函数,从头到尾就没有调用到,根本没用的函数,那么编译时,照样给予它能被分配内存的能力,但是前提是他要被执行到才行。(无视优化)
 
程序一运行,只运行了一半的代码,另一半空闲,那么自然就不会给另一半分配空间。
 
三、一个个分配,还是全部分配
 
据百度网友回答,是根据执行流程,以作用域为单位一起分配的。运行到哪个域,就把哪个域里面所有变量都先分配好。离开哪个域,哪个域集体删除。
 
四、声明与定义的区别
 
这个要说清太难了,专业术语一大堆,我根本解决不了,也懒得去深究。总之,百度回答,定义跟声明没有很清晰的划分界限。
 
我认为变量分配空间就叫定义,没分配就叫声明。这样对于我这个菜鸟来说好理解一点。所以int a; 是定义。 int a = 1; 是初始化。 
 
五、只是声明函数,编译时是否会生成对应代码
 
百度回答:无视优化情况下,会生成代码,这个代码只是告诉编译器,如果碰到定义的话,别说不认识。