C++是一门面向对象的编程语言,那类与对象也就是C++的核心部分,现在让我们一起来学习类与对象吧。

初识类与对象

  • 类的定义
  • 类的限定符
  • 封装
  • 类的实例化
  • 类对象模型
    • 类的大小
  • this指针

类的定义

定义一个类我们可以用到关键字structclass,在C语言中我们都学过结构体,对struct并不陌生。但是在C++中的struct与C中的结构体又有一些差距,可以这么说,就是因为C++兼容了C,才将struct保留下来。在C语言中的结构体,只能定义变量,使用变量,而在C++中的结构体,既可以定义变量,也可以定义函数。这就是C++中的类。

定义格式

//struct 为定义类的关键字,ClassName为类的名字,{}中为类的主体
struct className
{// 类体:由成员函数和成员变量组成
};

类中的元素称为类的成员:类中的数据称为类的属性或者成员变量; 类中的函数称为类的方法或者成员函数。

struct A
{//成员函数void SetStudentInfo(const char* name, const char* gender, int age) {strcpy(_name, name); strcpy(_gender, gender);_age = age;}void PrintStudentInfo(){cout << _name << " " << _gender << " " << _age << endl;}//成员变量char _name[20]; char _gender[3]; int _age;
};

但是在工作中,要完成一个大项目,往往都是声明和定义分离,那如何把类的声明和定义分离呢?声明部分引入成员变量和成员函数的声明,在定义部分通过类名 :: 函数名来定义

test.h文件中

struct A
{void SetStudentInfo(const char* name, const char* gender, int age);void PrintStudentInfo();char _name[20]; char _gender[3]; int _age;
};

test.cpp文件中

#include "test.h"//告诉编译器该函数属于类A中的成员函数void A::SetStudentInfo(const char* name, const char* gender, int age) {strcpy(_name, name); strcpy(_gender, gender);_age = age;}void A::PrintStudentInfo(){cout << _name << " " << _gender << " " << _age << endl;}

类的限定符

类的限定符有3种
1、public 公有
2、protected 保护
3、private 私有

初学阶段暂时把保护和私有看成是等价的。
类可以看做是一间房间,里面住着一家人,只有这家里的人才有劝访问家。这里的public相当于把家的大门打开了,谁都可以访问,而private是把门锁住了,谁都不能访问。但是在房间里了的人,可以互相访问。例如有public修饰的成员函数可以被外部访问,被private修饰的成员变量无法被类外访问。但是在同一个类中的成员函数可以访问成员变量。

struct A
{public:void SetStudentInfo(const char* name, const char* gender, int age) {strcpy(_name, name); strcpy(_gender, gender);_age = age;}void PrintStudentInfo(){cout << _name << " " << _gender << " " << _age << endl;}private:char _name[20]; char _gender[3]; int _age;
};

访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。
在C++中,我们更喜欢用关键字class来定义变量,class定义类和struct定义类的区别就是默认的限定符,class默认限定符是private,struct默认的限定符是public(兼容C)。

封装

面向对象的三大特性:封装、继承、多态
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行 交互
如何理解封装呢?
在现实生活中,相信大家都去过博物馆吧,当我们买票进入博物馆,我们参观博物馆,但是我们不能去修改或者去改变参观物的模型或者去乱写某某到此一游。再举一个例子和数据结构有关的。例如一个栈,栈中有入栈出栈等函数,也有栈的大小和容量。如果我们不进行封装,类外的人就可以随意修改栈的大小和容量,这样会导致我们无法正常操作这个类,如果进行了封装,那我们只能操作的是栈的一些函数,例如出栈入栈。

类的实例化

类就相当于盖楼前的图纸,并不能住人,只有当建造师通过图纸来实现真实的楼,才可以住人。而这里的类也一样,是有类被实例化了,才可以使用。每栋楼都有这些属性和函数,但是实例化后每栋楼的属性的可能不一样。一个类可以实例化出多个对象。
我们拿上一个代码来演示:

struct Student
{public:void SetStudentInfo(const char* name, const char* gender, int age) {strcpy(_name, name); strcpy(_gender, gender);_age = age;}void PrintStudentInfo(){cout << _name << " " << _gender << " " << _age << endl;}private:char _name[20]; char _gender[3]; int _age;
};int main()
{//实例化出一个对象,名为blackStudent black;//通过.来访问对象的成员函数,如果对象为指针,可以通过->来访问成员函数black.SetStudentInfo("白衬衫i", "男", 22); black.PrintStudentInfo();return 0;
}

运行结果:

类对象模型

类的大小

类的计算大小与C语言中的结构体大小计算方法是一样的。也是通过字节的对齐来计算。如果有不了解的读者,可以通过下面的链接来学习。
如何计算结构体大小.
但是在类中有成员函数,那成员函数会不会影响类的大小呢?
在C++中,类的成员方法是存在公共代码段中的,因为每个对象中成员变量是不同的,但是调用同一份函数,如果不存在公共代码段,当一个类实例化多个对象时,每个对象中都会保存一份代码,相同代码保存多次,浪费空间。所以类的成员函数实例化后是不会影响类的大小的,也及时不占空间的。
我们通过4个类来对类的大小进行测试:

class A
{public:void print(){cout << "A::print()" << endl;}
private:int _a;
};class B
{private:int _b;
};
class C
{public:void print(){cout << "C::print()" << endl;}
};
class D
{};int main()
{cout << "有函数有属性:" << sizeof(A) << endl;cout << "有属性没函数:" << sizeof(B) << endl;cout << "有函数没属性:" << sizeof(C) << endl;cout << "空类:" << sizeof(D) << endl;
}

测试结果:

通过前两个类我们可以得出类的成员函数时不占空间的,那为什么当只有函数时和空类却有大小,大小为什么为1呢?编译器给了空类一个字节来唯一标识这个类,表示这个类的存在。

扩展:
1、结构体进行内存对齐的原因:
平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常
硬件原因:经过内存对齐之后,CPU的内存访问速度大大提升。
2、如何让结构体按照指定的对齐参数进行对齐:
在结构体定义前加上#pragma pack(n)n为指定对齐数
3、如何知道结构体中某个成员相对于结构体起始位置的偏移量
通过地址相减 (char*)&A.member - (char*)&AA为类名,member为类的某个成员
4、什么是大小端?如何测试某台机器是大端还是小端
大端存储模式:就是内存的低地址上存着数据的高位,高地址上存着数据的低位。

小端存储模式:就是内存的低地址上存数据的低位,而高地址上存数据的高位。

用联合体,联合体也叫做共用体,它们共同占一个空间。

int check_sys()
{union UN{char c;int i;}un;un.i = 1;if (un.c == 1)return 0;//小端elsereturn 1;//大端
}

this指针

先看一下代码:

class Person
{public:void Display(){cout << _id << "-" << _age << "-" << _heigh << endl;}void SetInfo(int id, int age, int heigh){_id = id;_age = age;_heigh = heigh;}private:int _id;int _age;int _heigh;
};int main()
{Person p1, p2;p1.SetInfo(1, 18, 170);p2.SetInfo(2, 19, 175);p1.Display();p2.Display();return 0;
}

在上面代码的主函数中,我们分别实例化了两个对象p1和p2,也分别设置了他们的值,但是我们设置他们值,也就是调用他们的成员函数时,是怎么知道设置的哪一个对象呢,函数参数也没有对象的标识,这里面其实就是隐藏了一个参数,就是this指针。谁调用成员函数,就把谁的地址传给this指针。

p1.SetInfo(1, 18, 170); // == SetInfo(&p1,1,18,170);
p1.Display(); //==Display(&p1);

而且这个隐藏的this指针是函数的第一个参数,在我们的成员函数定义中,每个函数的第一个参数都是含有this指针的

void Display() //==void Display(Person* const this)
{}
void SetInfo(int id, int age, int heigh)
{} //==void SetInfo(Person* const this,int id,int age,int heigh)

this指针在成员函数中的参数格式为:类名* const this之所以是const,是防止该之指针改变指向的对象,这是不合理的,加上了const才使得对象更加安全。
在我们定义的setInfo函数中,里面的成员也是this指针的指向。只是我们往往会忽略不写,为了区分成员属性和函数参数名,我们通常在成员属性名前加上_,或者其他的标识符,用来区分他们的关系。

void SetInfo(int id, int age, int heigh){_id = id; //==this->_id = id_age = age;//==this->_age = age_heigh = heigh;//==this->_heigh= heigh}

但是并不是所有的成员函数都有this指针,只有在非静态的成员函数中才会有。且this指针不能在类外使用,只能在成员函数中使用。this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this 形参。所以对象中不存储this指针。我们的this指针属于函数形参,那就存放在栈上,但是在有些编译器中会进行优化,将this指针放到寄存器中(例如vs)。
this是一个指针,那他能不能是空指针呢?
答:可以为空,当我们调用函数时,如果函数内部不需要使用到this,也就是不需要通过this指向当前对象并对其进行操作时才可以为空(当我们在其中什么都不放或者在里面随便打印一个字符串)。如果调用的函数需要指向当前对象,并进行操作,则会发生错误(空指针引用)就跟C中一样不能进行空指针的引用。

C++ 初识类与对象相关推荐

  1. java基础教程 类_Java零基础系列教程06初识类和对象

    配套视频教程 万物皆对象 分类是人们认识世界的一个很自然的过程,在日常生活中会不自觉地进行分类 身边的对象 顾客 姓名-张浩 年龄-20 体重-60kg 操作: 购买商品 收银员 员工号-10001 ...

  2. Python基础之初识类和对象

    我们在前面学习了解了面向过程编程,接下来我们一起来学习一下面向对象编程.其实不管是面向过程,还是面向对 象,说白了就是一种编程方式而已.既然是面向对象编程,顾名思义,此编程方式的落地需要使用 &quo ...

  3. python对象不接受参数什么意思_python的类和对象2(self参数)

    python的类和对象2(self参数) 1.python里面对象的方法都会有self参数,它就相当于C++里面的this指针:绑定方法,据说有了这个参数,Python 再也不会傻傻分不清是哪个对象在 ...

  4. 类与对象初识 类是模具 对象是产品 0314 2101

    类与对象 程序中的类相当于生活中的模具 有一个模具可以创造无数个对象 同理 有一个类就可以创造无数个程序中的实体 关于对象 对象都具有两个特性: 特征(属性),名词 行为(方法),动词 日向雏田 类的 ...

  5. day16 初识面向对象编程(类与对象、构造函数与对象,类与类)

    目录 一.面向对象和面向过程的区别 二.类与对象的概念 三.构造函数和对象的关系 三.类与类的关系:组合 四.类与类的关系:依赖 一.面向对象和面向过程的区别 面向过程:强调过程步骤 面向对象:强调对 ...

  6. 初识类(classstruct)及C/C++封装的差异

    初识类(class&struct) 面向对象三大特性:封装.继承和多态.其中不得不谈的就是类,通过类创建一个对象的过程叫实例化,实例化后使用对象可以调用类成员函数和成员变量,其中类成员函数称为 ...

  7. python定义一个dog类 类属性有名字_python 基础 12 初识类,类方法,类属性

    python 基础 12 初识类,类方法,类属性 # 面向过程 : 想要一个结果 写代码 实现计算结果 # 面向对象开发 : 有哪些角色 角色的属性和技能 两个角色之间是如何交互的 # 复杂的 拥有开 ...

  8. python3对象初始化_Python 面向对象概念 类和对象 对象初始化__init__ 绑定与非绑定...

    面向对象 (Object Oriented Programming,简称OOP) 1.什么是面向对象:面向对象编程是一种思想,它指导程序员如何编写出更好的程序.它的核心是对象,此时程序员从操作者变成了 ...

  9. 类和对象1-构造函数、析构函数

    文章目录 类和对象 构造函数 构造函数的特性 const修饰类的成员函数 析构函数 类和对象 如果一个类中我们自己什么成员也没有给出,我们称之为空类.但是要注意的是空类并不是真的什么都没有,任何一个类 ...

最新文章

  1. 复旦副教授魏忠钰:AI和人类对垒「奇葩说」,如何打造智能辩手?
  2. 最新大脑图谱研究表明,手部的运动区域也与整个身体相连
  3. 区域链结构对于数据中心有什么影响?这个影响是好是坏呢!
  4. Redis集群读写分离架构搭建以及主从数据连通验证(附加集群口令认证以及Redis端口6379释放)
  5. LUA __call
  6. 不能输入_为什么稳压器输入端不能配漏电保护器
  7. xxl-job源码分析
  8. SRV记录注册不成功的可能的原因
  9. 3d在调试区输出坐标_CSS3如何实现一个 3D 效果的魔方
  10. FIle类常用工具方法整理(持续更新)
  11. 在一家公司产生倦怠感,如何化解?
  12. 钱放在支付宝好,还是微信好,还是存在银行好?
  13. Bailian4100 进程检测【排序】
  14. python 怎么表示阶乘_python表示阶乘
  15. 144.绘制布朗运动曲线
  16. python在文本添加超链接_在Markdown中快速插入超链接的Workflow
  17. Python报错:ValueError: operands could not be broadcast together with shapes
  18. vbox虚拟机无法使用计算机名称,Vbox虚拟机 所选虚拟电脑不能正常访问
  19. 计算机网络专业运动会入场式,这所学校运动会开幕式亮了!各方阵带着专业C位亮相...
  20. 华为云-实时流计算服务CS

热门文章

  1. ORACLE 11GR2 RAC new features 新特性。
  2. 客户端负载均衡及透明应用切换(TAF)tnsnames failover=on
  3. 十字路口待转区什么用_都知道“左转待转区”,但到底该怎么走?老司机给你一次讲清楚...
  4. 玩转springboot2.x之自定义项目内自动配置
  5. retrofit框架学习(一)----基本用法
  6. android studio 中使用lambda表达式
  7. hrbp 牵着鼻子走_防止被下属牵着鼻子走的四个经典方法,学会了,下属就好管了...
  8. matlab实验5函数文件,实验五M文件和MATLAB设计技术总结.doc
  9. react.js 给标识ref,获取内容
  10. ex28 布尔表达式练习