c++编程(3)——类和对象(1)、类

news2024/11/25 12:52:38

欢迎来到博主的专栏——c++编程
博主ID:代码小豪

文章目录

    • 对象
    • 类的访问权限
    • 类的作用域

c++最初对c语言的扩展就是增加了类的概念,使得c语言在原有的基础之上可以做到信息隐藏和封装。

那么我们先来讲讲“带类的c”与C语言相比有什么改进。

先讲讲类是什么,举个例子,小明男性、身高一米7,体重70kg,小美女性,身高一米6,体重60kg。他们两都是同属一个类的——人类。我们需要在类中定义出对象的行为和属性,那么人类如下:

class human {
	int age;//年龄
	int weight;//体重
	int high;//身高
	const char* gender;//性别
};

对象

用类创建对象的过程,叫做类的实例化。

如果将对象类比为房屋,那么类就是房屋的设计图。
在这里插入图片描述
一个类可以实例化多个对象,这些对象会拥有相同的属性,但是属性的值是多少,则是由程序员决定的。

就好比房子一样,如果使用的设计图一样,那么这些房屋的构造,面积都是一样的,至于内部的不同,则是看房子的主人是如何装修,以及摆放的家具了。

我们回到human的使用上。我们用类“human”实例化出两个对象,一个小明、一个小美,对象之间拥有的属性都是一致的,如:性别、年龄、体重。但是对象之间的属性值是可以有差异的。

class human {
	int age;//年龄
	int weight;//体重
	int high;//身高
	const char* gender;//性别
};
int main()
{
	human xiaoming;//创建对象小明
	human xiaomei;//创建对象小美

	xiaoming.age = 16;//小明的年龄
	xiaoming.gender = "boy";//性别
	xiaoming.high = 170;//身高
	xiaoming.weight = 70;//体重

	xiaomei.age = 17;//小美的年龄
	xiaomei.gender = "girl";//小美的性别
	xiaomei.high = 160;//身高
	xiaomei.weight = 60;//体重
}

熟悉C语言的人就发现了,这c++的类和C语言的结构体没什么区别啊。为什么称为类呢?

前面提到了,类不仅能定义对象的属性,还能定义对象的行为,属性很好理解,就是在类里面定义成员变量呗,C语言的结构体也能定义成员变量,那么对象的行为是什么呢?

在c++的类中,不仅仅能定义成员变量,还能定义成员函数,这在C语言的结构体中是不能实现的。

以定义一个栈为例。

typedef int STDataType;
class stack {
	void Init(int capacity)//栈的初始化
	{
		_stack = (STDataType*)malloc(sizeof(STDataType) * capacity);
		_capacity = capacity;
		_top = 0;
	}

	STDataType Top()//取栈顶元素
	{
		return _stack[_top - 1];
	}

	bool Empty()//判断栈是否为空
	{
		return _top == 0;
	}

	void Pop()//弹出栈顶
	{
		if (Empty())
		{
			cout << "stack is empty" << endl;
			return;
		}
		_top--;
	}

	void Push(STDataType e)//入栈操作
	{
		if (_top == _capacity)//扩容
		{
			int newcapacity = _capacity == 0 ? 4 : 2 * _capacity;
			STDataType* tmp = (STDataType*)realloc(_stack, sizeof(STDataType) * newcapacity);
			if (tmp == nullptr)
			{
				perror("malloc fail\n");
				return;
			}
			_stack = tmp;
			_capacity = newcapacity;
		}
		_stack[_top++] = e;
	}

	void Destory()
	{
		free(_stack);
		_top = 0;
		_stack = NULL;
		_capacity = 0;
	}

	STDataType* _stack;
	int _top;
	int _capacity;
};

这是一个栈的类。用这个类可以实例化一个栈。调用栈中的函数会对这个对象内的数据进行操作。

如:

int main()
{
	stack s1;//实例化栈s1
	s1.Init(4);//栈s1初始化

	s1.Push(1);//入栈s1
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	s1.Push(5);

	while (!s1.Empty())
	{
		cout << s1.Top() << ' ';//取s1栈顶元素
		s1.Pop();//弹出s1栈顶
	}

	s1.Destory();//销毁栈s1
	return 0;
}

但是如果大家尝试运行这段代码,编译器会报错。
在这里插入图片描述

类的访问权限

类可以完成信息的隐藏,在一个类中,所有的成员的默认权限都是隐藏。如果想要对类中成员的权限进行管理,就要使用访问限定符了。

c++中的访问限定符有3个,public(公开),protect(保护),private(隐藏)。

访问限定符的作用如下:

(1)public是公开成员,public修饰的成员可以在类外直接引用
(2)protect,private修饰的成员在类外不能被引用
(3)访问权限的作用域从该限定符出现的位置,直到下一个限定符出现的位置为止
(4)最后一个限定符的作用域是从该限定符出现的位置,一直到类的结尾(})为止
(5)类的所有成员的默认状态都是private。

可以看到类stack中,没有成员的权限限定符,因此所有的成员都是private。因此在类外引用成员函数时,编译器会报错。

解决方法就是在类的开头加上限定符public。

typedef int STDataType;
class stack {
public:
     //省略…………
};

但是我们仔细想想,类stack中的所有成员都应该公开吗?

首先是类中的成员函数,这些成员函数时提供外部使用的,因此需要公开。

而类中的成员变量呢?需不需要公开?我们先来想这么一个问题。栈的成员变量能不能被修改。比如将_stack公开之后,我们就能在外部将_stack置为空指针。那么会不会在某个不经意的操作之后,这个_stack就成为了空指针,或者野指针。这当然是可能的。

	s1._stack = nullptr;

通过判断,类stack的成员变量不需要公开。因此类stack的设定应该改为。

typedef int STDataType;
class stack {
public:
	void Init(int capacity)//栈的初始化
	{
		_stack = (STDataType*)malloc(sizeof(STDataType) * capacity);
		_capacity = capacity;
		_top = 0;
	}
	//省略以下成员函数
private:
	STDataType* _stack;
	int _top;
	int _capacity;
};

类中的什么信息需要隐藏,需要公开,都是需要程序员自己判断之后决定的。通常来说,如果某个变量或函数是需要在类的外部使用的,则需要公开这些成员。若是某个变量或函数在外部使用会影响对象的使用的话(比如将stack中的_stack修改会导致程序崩溃),则将这些成员设为private。

类的作用域

类的作用域也称为类域。通常来说,类都是定义在头文件中的,而头文件中的类的成员函数都是声明。定义会放在另外一个包含这个头文件的源文件,这是为了避免出现重复定义的编译错误(想要更深刻了解,可以去学习一下“编译与连接”)。

那么上面说的类stack,那么它在头文件“stack.h”中的定义如下:

typedef int STDataType;
class stack {
public:
	void Init(int capacity);//栈的初始化

	STDataType Top();//取栈顶元素

	bool Empty();//判断栈是否为空

	void Pop();//弹出栈顶

	void Push(STDataType e);//入栈操作

	void Destory();

private:
	STDataType* _stack;
	int _top;
	int _capacity;
};

我们将这些成员函数的定义放在源文件中。

在这里插入图片描述

但是此时编译器就报错了。可以看到整个源文件的报错满满当当。目前,我们了解的c++的域有全局域,局部域,命名空间域。现在我们来了解第四个域,类域。

首先,我们定义在“stack.cpp”中的函数是存在于局部域的。但是类中的定义与变量却是定义在类域当中的。定义在全局域的函数和变量可以在其他域中使用,而类域中的函数不能定义在全局域。若是需要将函数定义在类外就需要使用域限定符。这是c++规定的

因为大家可以设想一下。c++是支持重载函数的。如果我可以在全局域中定义类stack的初始化函数Init。那么我也可以定义一个是用于队列的初始化函数Init,既然这两个函数都能存在,那么当我们调用初始化函数Init时,应该调用哪个函数呢?这个就导致了歧义的存在,因此c++新增了一个类域,定义在域外的成员需要使用域限定符(::)指明成员属于哪个域。

因此,stack的成员函数的正确定义的方法是在函数名前面加上限定的域(注意,域限定符使用在函数名之前)。

#include"stack.h"

void stack::Init(int capacity)//栈的初始化
{
	_stack = (STDataType*)malloc(sizeof(STDataType) * capacity);
	_capacity = capacity;
	_top = 0;
}

STDataType stack::Top()//取栈顶元素
{
	return _stack[_top - 1];
}

bool stack::Empty()//判断栈是否为空
{
	return _top == 0;
}

void stack::Pop()//弹出栈顶
{
	if (stack::Empty())
	{
		cout << "stack is empty" << endl;
		return;
	}
	_top--;
}

void stack::Push(STDataType e)//入栈操作
{
	if (_top == _capacity)//扩容
	{
		int newcapacity = _capacity == 0 ? 4 : 2 * _capacity;
		STDataType* tmp = (STDataType*)realloc(_stack, sizeof(STDataType) * newcapacity);
		if (tmp == nullptr)
		{
			perror("malloc fail\n");
			return;
		}
		_stack = tmp;
		_capacity = newcapacity;
	}
	_stack[_top++] = e;
}

void stack::Destory()
{
	free(_stack);
	_top = 0;
	_stack = NULL;
	_capacity = 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1589589.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利用SARscape对日本填海造陆和天然气开采进行地表形变监测

日本千叶市&#xff0c;是日本南部重要的工业港市。位于西部的浦安市是一个典型的"填海造田"城市&#xff0c;东南部的东金区有一片天然气开采区域&#xff0c;本文利用SARscape&#xff0c;用干涉叠加的方法&#xff0c;即PS和SBAS&#xff0c;对这两个区域进行地表…

电磁兼容导论翻译疑问

在读电磁兼容导论P71页时&#xff0c;发现在“注意“这句话翻译的和原文有疑问&#xff1a;我的理解是单边幅度谱是双边幅度谱的两倍。请大家帮忙看看应如何翻译。 英文原版&#xff1a;Note that all positive frequency components except the dc component in the two-side…

红黑瓷砖(BFS和DFS)

9 6 ....#. .....# ...... ...... ...... ...... ...... #...# .#..#.45BFS import java.util.Deque; import java.util.LinkedList; import java.util.Scanner;public class Main {//. 黑色//# 红色// 黑色开始static final int N 11;static int n,m,ans 1; static char[][…

Learn SRP 01

学习链接&#xff1a;Custom Render Pipeline (catlikecoding.com) 使用Unity版本&#xff1a;Unity 2022.3.5f1 1.A new Render Pipeline 1.1Project Setup 创建一个默认的3D项目&#xff0c;项目打开后可以到默认的包管理器删掉所有不需要的包&#xff0c;我们只使用Unit…

竞赛课第六周(树状数组的应用)

实验内容: HDU 1166 敌兵布阵【线段树】 线段树的应用 敌兵布阵 C国的死对头A国这段时间正在进行军事演习&#xff0c;所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取…

mybatis-puls-配置日志

#日志配置 mybatis-plus.configuration.log-implorg.apache.ibatis.logging.stdout.StdOutImpl 我们所有的sql现在是不可见的&#xff0c;我们希望知道它是怎么执行的&#xff0c;所以我们必须要看日志

【示例】MySQL-SQL语句优化

前言 本文主要讲述不同SQL语句的优化策略。 SQL | DML语句 insert语句 插入数据的时候&#xff0c;改为批量插入 插入数据的时候&#xff0c;按照主键顺序插入 大批量插入数据的时候&#xff08;百万&#xff09;&#xff0c;用load指令&#xff0c;从本地文件载入&#x…

springCloud项目打包 ,maven package或install打包报错

解决思路一&#xff1a; <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.7.RELEASE</version></plugin><plugin>&…

MySQL中的SQL高级语句[二]

使用语言 MySQL 使用工具 Navicat Premium 16 代码能力快速提升小方法&#xff0c;看完代码自己敲一遍&#xff0c;十分有用 拖动表名到查询文件中就可以直接把名字拉进来以下是使用脚本方法&#xff0c;也可以直接进行修改中括号&#xff0c;就代表可写可不写 有些地方的代…

在Ubuntu上安装Docker Compose

Docker Compose 是一个用于定义和管理Docker容器的工具&#xff0c;它使用yml来配置应用的服务、网络和卷等。特别是在定义多个容器时&#xff0c;它非常擅长定义多个容器之间的关系和依赖。 第一步&#xff1a;更新软件包 sudo apt update第二步&#xff1a;安装网络工具cur…

我企业的业务需要制作企业网站吗?11个支持的理由以及5个反对的理由!

如果你的企业经营得还不错&#xff0c;你可能会找出很多理由&#xff0c;说明为什么一个高效的网站对你来说并不那么重要。确实&#xff0c;你明白企业需要在互联网上有一定的存在感&#xff0c;但你可能并不认为一个高效的网站会对你的特定业务产生太大的影响——尤其是当你已…

无尘净化棉签:医药、化妆品及工业应用中的重要角色及防静电特性

无尘净化棉签是一种在医药、化妆品、电子光电产品、半导体、光学、磁头清洗、视频头、清洗头等领域广泛应用的清洁工具。本文探讨了无尘净化棉签在这些领域中的重要性&#xff0c;并特别关注了其防静电特性对产品质量和性能的影响。 无尘净化棉签是一种专为减少或避免产生灰尘和…

MySQL分区表(14/16)

分区表 基本概述 分区表是数据库中一种用于优化大型表数据管理和查询性能的技术。它将一个表的数据根据特定的规则或条件分割成多个部分&#xff0c;每个部分称为一个分区。每个分区可以独立于其他分区进行存储、管理和查询&#xff0c;这样可以提高数据处理的效率&#xff0…

代码随想录第38天| 509. 斐波那契数 70. 爬楼梯

理论基础 刷题大纲&#xff1a; 动态规划5步曲&#xff1a; 1、确定dp数组以及下标的含义 2、确定递推公式 3、dp数组如何初始化 4、确定遍历顺序 5、举例推导dp数组 509. 斐波那契数 509. 斐波那契数 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.co…

羊大师春季运动受伤应急妙招

春季运动时受伤是很常见的情况&#xff0c;特别是在户外活动中。了解一些应急妙招&#xff0c;可以帮助你在受伤时进行初步处理&#xff0c;减轻伤害。以下是几种常见运动伤害的应急处理方法&#xff1a; 扭伤和拉伤 休息&#xff1a;立刻停止运动&#xff0c;避免对受伤部位…

安达发|APS软件系统助力高端装备制造业高质量发展

APS&#xff08;Advanced Planning and Scheduling&#xff0c;高级计划与排程系统&#xff09;软件系统在高端装备制造业中的应用&#xff0c;对于推动行业高质量发展具有重要作用。以下是对这一主题的详细探讨&#xff1a; 高端装备制造业指那些技术含量高、附加值大、市场竞…

Windows 关闭占用指定端口的进程

以下示例以443端口为例&#xff0c;具体哪个端口视自己情况而定 输入命令 # 输出的最后一列就是进程号pid netstat -ano | findstr "443" 找出占用443端口的进程号(pid)&#xff08;第二列是你本机的应用占用的端口&#xff0c;看第二列就行&#xff09;如下图&am…

二叉查找树、二叉搜索树、二叉排序树算法分析及实现

一、几个概念 二叉树&#xff08;Binary Tree&#xff09;&#xff0c;是 n&#xff08;n > 0&#xff09;个结点&#xff08;每个结点最多只有2棵子树&#xff09;的有限集合&#xff0c;该集合或为空集&#xff0c;称为空二叉树&#xff0c;或由一个根节点和两颗互不相交…

算法练习第16天|101. 对称二叉树

101. 对称二叉树 力扣链接https://leetcode.cn/problems/symmetric-tree/description/ 题目描述&#xff1a; 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#x…

稀碎从零算法笔记Day46-LeetCode:互质树

这几天有点懈怠了 题型&#xff1a;树、DFS、BSF、数学 链接&#xff1a;1766. 互质树 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给你一个 n 个节点的树&#xff08;也就是一个无环连通无向图&#xff09;&#xff0c;节点编号从 0 到 …