当前位置: 首页 > ds >正文

C++:类和对象(上)

一、引言

        类和对象是C语言所没有的,也是非常重要的一部分,理解它至关重要。

        C++中的类是面向对象编程的核心概念,它是一种用户自定义的数据类型,用于封装数据(属性)和操作数据的方法(函数)。类定义了对象的蓝图或模板,描述了对象应具备的特征和行为。对象则是类的具体实例,是根据类定义创建的实际实体,占用内存空间并包含具体的属性值。通过类和对象,C++实现了封装、继承和多态等面向对象特性,使代码更模块化、可重用和易于维护。

二、类的定义

2.1、类的定义格式

 class 为类的关键字,具体语法形式如下:

class name   //name为类的名字,自己取
{//……类的成员,可以为变量,可以为函数等};   //分号不能省略

(1)类的成员名称为了区分,要在前面加上 " _ " 或者 " m " 或者其他,具体看公司要求;

(2)struct 也可以充当关键字来定义类,与C语言不同的是,C++中的struct的成员可以为函数。但是,我们还是推荐使用 class 定义类;

(3)在类的内部定义的函数,都默认为内联函数;如果不想内联,可以在类中声明,然后在外部定义;

(4)类一般定义在头文件中。

2.2、类的访问限定符

        类的访问限定符:就是用来限定类的内部成员权限的符号。共有三个:private ,public ,protected 。

2.2.1、private (私有)

用法如下:

class student
{
private:int number;char[10] name;int age;int sex;
};

private 意味着私有,也就是只能在Student 内部访问,不能在外部访问。例如,下面的代码就是错误的,因为访问了私有成员。

Student student1;
std::cout << student1.name << endl;

对了,如果类的成员变量什么访问限制符都没有,则默认为被 private 修饰。

2.2.2、public (公有)

public 意思是公有,可以被外部访问。用法和private一样,如下:

class Student
{
private:int number;int age;char[10] name;
public:void DisplayAge(){cout << "学生年龄:" << age << endl;}
};

一般我们会把函数成员放在公有部分,私有部分一般都是存放一些数据的。

2.2.3、protected (保护)

用法和上面两个一样,这里不多说。

被 protected 修饰的成员为保护成员,在外部不能直接访问,只有通过派生类和内部才能访问。(派生类后面会将)

注意:这三个访问限定符没有先后之分,你可以先写公有部分,也可以先写私有部分

2.3、类域

(1)类域就是类定义的一个新的作用域,类的所有成员都在类的作用域中。在类的外部定义成员要用 :: ;

(2)类域影响编译器的查找规则。如果在调用一个函数时,没有指定类域,那么编译器就会默认该函数为全局函数,会在全局寻找其定义和声明,如果没有搜索到就会报错。

三、类的实例化

3.1、实例化的概念

创建一个类,只是创建了一个类,只是告诉编译器有这样的一个类,使用了吗?没有使用。你可以类比C语言中的结构体,你只是声明了一个结构体,并没有使用,使用结构体首先需要创建一个变量,类也是如此。

简单来说,类的实例化就是用类创建一个对象。一个类可以创建很多的对象。例如:

class Student
{
private:int _age;char[10] _name;
public:void SetInfo(int age, char* name){_age = age;_name = name;}
};int main()
{Student student1;   //实例化SetInfo( 18 , "zhangsan" );return 0;
}

3.2、对象的大小

用类创建一个对象叫实例化,系统就会给这个对象分配一个空间,那么这个空间有多大呢?里面的成员要不要遵循对齐原则?

3.2.1、对齐原则

        对象是存在内存对齐的,规则同C语言的结构体对齐,这里就省略了。

3.2.2、成员函数的储存

        对象中的内存里没有成员函数的位置。成员函数会单独放在一个地方等着调用。

3.2.3、空的类的对象的大小

求下面类创建的对象的大小:

class B
{};

最后结果是1,开辟1个字节的空间就是为了标记这个类的对象存在过。就像唯一能证明她来过的只有心里的那道疤痕

四、this 指针

先看以下代码,记住两个对象 s1 和 s2 。

class Student
{
private:int _age;int _number;char[10] _name;
public:void ShowData(){cout << "学生的学号:" << _number << endl;cout << "学生的姓名:" << _name << endl;cout << "学生的年龄:" << _age << endl;}//…………
};int main()
{Student s1;Student s2;//…………填写学生信息s1.ShowData();s2.ShowData();return 0;
}

好,我们可以看到,s1 和 s2 都分别调用了打印各自数据的函数。但是,函数是不会存储在对象中的,而是其他地方,所以,s1 和 s2 调用的同一个函数。问题来了,这个函数如何区分到底打印 s1 的数据还是 s2 的数据呢?答案就在 this 指针。

原来,编译器会在类的成员函数的第一个参数添加一个新的参数,叫 this指针。实际上,ShowData函数的原型为:

void ShowData( Student* const this)
{cout << "学生的学号:" << this->_number << endl;cout << "学生的姓名:" << this->_name << endl;cout << "学生的年龄:" << this->_age << endl;
}

通过 this 指针,函数就能区分到底该打印谁了。

注意:C++规定,不能在函数的实参和形参的位置写出 this 指针 ,但是可以在函数内部写出this指针。

练习:下面的代码是正常运行还是运行崩溃?

using namespace std;
class A
{
public:void Print()    {cout << "A::Print()" << endl;}
private:int _a;
};int main()
{A* p = nullptr;p->Print();return 0;
}

答案是正常运行。虽然 p 为空指针,还引用了成员函数Print(),但是,成员函数储存在别的地方,在编译的时候就已经确定了,所以不会报错。但是,如果成员函数涉及this指针的解引用,那就会报错了,因为空指针不能解引用。

五、C语言和C++实现栈的对比

C的代码就不放到这里了,大家都会。

下面是C++版本的栈:

//创建一个栈的C++版本
typedef int StackDataType;
class Stack
{
private:StackDataType* _arr;int _top;int _capacity;
public://栈的初始化void StackInit(){assert(this);_arr = nullptr;_top = _capacity = 0;}//入栈void StackPush(StackDataType x){if (_top == _capacity){int newCapacity = _capacity == 0 ? 4 : 2 * _capacity;StackDataType* tmd = (StackDataType*)realloc(_arr ,sizeof(StackDataType) * newCapacity);if (tmd == nullptr){perror("malloc fail!");exit(1);}_arr = tmd;_capacity = newCapacity;}_arr[_top++] = x;}//判断栈是否为空bool StackEmpty(){return _top == 0;}//出栈void StackPop(){assert(!StackEmpty());_top--;}//取栈顶StackDataType StackTop(){assert(!StackEmpty());return _arr[_top-1];}//销毁栈void StackDestory(){if (_arr)free(_arr);_arr = nullptr;_top = _capacity = 0;}//打印栈void StackPrint(){assert(!StackEmpty());for (int i = 0; i < _top; i++){cout << _arr[i] << " ";}cout << endl;}
};
int main()
{Stack s1;s1.StackInit();s1.StackPush(1);s1.StackPush(2);s1.StackPush(3);s1.StackPush(4);s1.StackPush(5);s1.StackPrint();s1.StackPop();s1.StackPrint();s1.StackDestory();return 0;
}

感觉C++更好用,把这些函数都封装了起来,而且使用起来更加方便。建议读者下去要亲自敲几个类体验体验!才能体会到类的魅力。

六、结语

        到这里,就已经认识,会用类了。但这还远远不够,更多细节还在后面,比如类里面自带的几个函数等。加油,追梦人!

http://www.xdnf.cn/news/20052.html

相关文章:

  • 微软rStar2-Agent:新的GRPO-RoC算法让14B模型在复杂推理时超越了前沿大模型
  • 卷积操作原来分3种
  • 2025年工科生转型必考的十大高含金量证书!
  • 腾讯云建站多少钱?2025年最新价格曝光,0基础也能做出专业网站?实测真假
  • flutter专栏--深入剖析你的第一个flutter应用
  • 从一次Crash分析Chromium/360浏览器的悬空指针检测机制:raw_ref与BackupRefPtr揭秘
  • 留学第一天,语言不通怎么办?同声传译工具推荐来了
  • 常用假设检验方法及 Python 实现
  • 亚马逊云代理商:配置安全组规则步骤
  • kafka Partition(分区)详解
  • nestjs 阿里云服务端签名
  • 深度学习篇---SGD+Momentum优化器
  • Photoshop - Photoshop 触控手势
  • 电表连网不用跑现场!耐达讯自动化RS485转Profinet网关 远程配置+技术支持,真能做到!
  • ASP.NET 实战:用 SqlCommand 打造一个安全的用户注册功能
  • SIC8833芯片智能充气泵设计方案
  • 原创未发表!POD-PINN本征正交分解结合物理信息神经网络多变量回归预测模型,Matlab实现
  • 第二家公司虽然用PowerBI ,可能更适合用以前的QuickBI
  • pip completion工具作用(生成命令行自动补全脚本)(与pip-bash-completion区别)
  • 东土智建 | 让塔吊更聪明的“四大绝技”工地安全效率双升级
  • EasyMeeting-注册登录
  • PDF-XChange Editor:全功能PDF阅读和编辑软件
  • 《华为基本法》——企业文化的精髓,你学习了几条?
  • 技术实战:从零开发一个淘宝商品实时数据采集接口
  • 《嵌入式硬件(一):裸机概念与80c51单片机基础》
  • Docker 运行 PolarDB-for-PostgreSQL 的命令,并已包含数据持久化配置
  • Scrapy框架实战:大规模爬取华为应用市场应用详情数据
  • 实现 TypeScript 内置工具类型(源码解析与实现)
  • C语言中的运算符
  • 自动化运维-ansible中的条件判断