文章目录
- 前言
- 1.面向过程和面向对象初步认识
- 2.引入类的概念
- 1.概念与用法
- 2.类的访问限定符及封装
- 3.类的作用域和实例化
- 4.类的大小计算
- 8.this指针
- 3.总结
前言
本文将对C++面向对象进行初步介绍,引入类和对象的概念。围绕类和对象介绍一些基础知识,为以后深入学习C++打基础
1.面向过程和面向对象初步认识
之前C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。而C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
洗衣服为例
面向过程是把洗衣服的每个步骤都分析确定好,最终完成洗衣服的任务。
面向对象是把洗衣服抽象成4个对象:人+衣服+洗衣机+洗衣粉。具体过程是人将衣服和洗衣粉倒入洗衣机,启动洗衣机。至于洗衣粉和衣服这么放入洗衣机的,洗衣机是怎么洗的这些都漠不关心。
2.引入类的概念
1.概念与用法
为了支持面向对象的思想C++引入了类的概念,C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。这个时候结构体就不能称为结构体体了,应该称为类。类可以简单看作是一种特殊的结构体。
C++中常用关键字class来定义类
class className
{
// 类体:由成员函数和成员变量组成
}; // 一定要注意后面的分号
class为定义类的关键字,className为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略.
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。
类的两种定义方式:1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
2. 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::
一般来说,更建议使用第二种用法.
2.类的访问限定符及封装
之前C语言的结构体中的成员变量访问不收限制比较自由,但是C++比较讲究封装性,C++为了保证其封装性引入了访问限定符的概念。
【访问限定符说明】
1. public修饰的成员在类外可以直接被访问
2. protected和private修饰的成员在类外不能直接被访问 (此处protected和private是类似的)
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止.
4. 如果后面没有访问限定符,作用域就到 } 即类结束。
5. class的默认访问权限为private,struct为public(因为struct要兼容C)
在C++中也是支持用struct来定义类的,但是一般不建议使用
C++中strcut和class的区别是什么?
C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private。注意:在继承和模板参数列表位置,struct和class也有区别,后序再介绍。
关于封装这里简单说一下
C++面向对象的三大特性:封装、继承、多态。在类和对象阶段主要就是围绕着封装特性学习。
那什么是封装呢?封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。封装本质上是一种管理,让用户更方便使用类。
比如:对于电脑这样一个复杂的设备,提供给用户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日常事务。对于电脑内部的细节用户不需要关心.在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用
3.类的作用域和实例化
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
之前在类外定义函数时就使用了::来指明函数属于哪个类域
类的实例化
用类类型创建对象的过程,称为类的实例化。
类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量.
做个比方:类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间.
4.类的大小计算
类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算一个类的大小?
类中只保存成员变量,成员函数存放在公共的代码段。因为每个对象的数据都是独立的,也就是成员变量是独立的,但是成员函数每个类都会调用这是共享的。一个类的大小,实际就是该类中”成员变量”之和,不过是按照内存对齐规则来分配成员变量的空间。
关于内存对齐之前C语言的博客有过介绍,这里不过多的解释。注意空类的大小,空类比较特殊,编译器给了空类1个字节来唯一标识这个类的对象存在过。
8.this指针
在介绍this指针之前,我们来看一段代码。
init函数是怎么区分对象a1和a2的,它怎么知道自己是被哪个对象调用的呢?其实C++中通过引入this指针解决该问题,即:
C++编译器给每个"非静态的成员函数"增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。
只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
当然this指针也可以显示调用,当然这样没必要
思考两个问题:1.this指针存在于哪里?2. this指针可以为空吗?
对于第一个问题,this指针是作为成员函数的隐藏参数的,所以它也是属于函数参数。既然是函数参数那么它就存在于函数栈帧中也就是栈上。
对于第二个问题,我们来看看这样的两段代码。
代码1
代码2
代码1是不会崩溃的,代码2是会发生崩溃的,这是为什么呢?
变量虽然是空指针,但是代码1中的this指针并没有发生解引用的行为,仅仅是用来调用Print函数,让Print函数知道自己是被哪个对象调用的,但是代码2是访问到了类中的成员,访问类中的成员是需要this解引用的,这样一来就会对空指针解引用引发错误。所以this指针在代码1的情况下可以为空,但是在代码2这样的情况下就不能为空。
其实我们写下这样的代码也是没问题的
因为实际上并没有发生解引用的行为,如果将*p赋值给某个变量的化,产生了写入的动作这样才算是发生了解引用的行为。
3.总结
在C语言结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体中,即数据和操作数据的方式是分离开的,而且实现上相当复杂一点,可能涉及到大量指针操作,稍不注意可能就会出错。C语言的风格相对来说比较自由,但是这种自由就要求程序员对代码的掌握的比较细致周全。
C++中通过类可以将数据 以及 操作数据的方法进行完美结合,通过访问权限可以控制那些方法在类外可以被调用,即封装,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。用户在使用时也不必关注底层实现细节,而且每个方法不需要传递结构体指针的参数了,编译器编译之后该参数会自动还原,即C++中 函数成员参数是编译器维护的,C语言中需用用户自己维护。
补充一点在C++中类的成员的命名方式
class Date
{
public:
void Init(int year)
{
// 这里的year到底是成员变量,还是函数形参?
year = year;
}
private:
int year;
};
为了避免将类中的成员变量和成员函数参数搞混淆,我们一般尽量不要将变成员变量和成员函数的参数命名一样,推荐下面的这样的做法
class Date
{
public:
void Init(int year)
{
_year = year;
}
private:
int _year;
};
这就是一种比较好的命名风格
以上内容,如有错误欢迎指正!