C++类与对象(1)—初步认识

这篇具有很好参考价值的文章主要介绍了C++类与对象(1)—初步认识。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、面向过程和面向对象

二、类

1、定义

2、类的两种定义方式 

3、访问限定符

4、命名规范化 

5、类的实例化

6、计算类对象的大小

7、存储方式

三、this指针 

1、定义 

2、存储位置

3、辨析

 四、封装好处

下一篇:构造函数&析构函数


一、面向过程和面向对象

  • C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
  • C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

面向过程和面向对象是两种主要的编程范式。它们的主要区别在于如何组织代码和处理数据。

1. 面向过程编程:

面向过程编程是一种编程范式,它以过程(也称为函数)为中心,数据和过程是分开的。在面向过程编程中,程序是一系列被调用的函数或过程,数据被视为辅助函数运行的附属物。这种编程范式的主要特点是流程化,按照事物处理的逻辑顺序来编写程序。

例如,假设我们要编写一个程序来制作一杯咖啡。在面向过程的编程中,我们会创建一个函数来热水,一个函数来研磨咖啡豆,一个函数来混合水和咖啡,等等。每个函数都有一个明确的任务,并按照特定的顺序执行。

2. 面向对象编程:

面向对象编程是一种编程范式,它将数据和处理数据的函数组合成一个整体,称为“对象”。在面向对象编程中,程序是由对象组成的。每个对象都包含数据(称为属性)和一组处理数据的函数(称为方法)。这种编程范式的主要特点是封装性,继承性和多态性。

还是以制作咖啡为例,面向对象编程会创建一个“咖啡”对象,这个对象有一些属性(如水,咖啡豆等)和一些方法(如热水,研磨咖啡豆,混合水和咖啡等)。所有的操作都是通过操作对象的方法来完成的。

二、类

C语言结构体中只能定义变量,而在C++中,结构体不仅可以定义变量,也可以定义函数。

在C++中把结构体升级成了类,而且结构体的名字就是类型。

//C++兼容C结构体用法
typedef struct ListNode
{
	int val;
 //C struct ListNode是类型
	struct ListNode* next;
}LN;

struct ListNode
{
	int val;
 //C++ ListNode是类型
	ListNode* next;
};

1、定义

class className
{
    // 类体:由成员函数和成员变量组成

};  // 一定要注意后面的分号
  • class为定义类的关键字(C语言中用struct),ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。
  • 类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。

2、类的两种定义方式 

在之前数据结构中学过的栈,因为用C语言实现,结构体中只能定义变量,现在我们可以通过C++的方式实现栈,这样在结构体中也可以定义函数。  

第一种:声明和定义全部放在类体中 

注意:

  • 成员函数和成员变量定义在类中的位置没有要求,在调用时会在整个类中查找,不会像类之外使用变量或函数时,编译器只会向上查找。 
  • 成员函数如果在类中定义,编译器可能会将其当成内联函数处理。

这里出现了public和private,他们是访问限定符,稍后进行讲解。 

class Stack
{
public:
	// 成员函数
	void Init(int n = 4)//缺省参数
	{
		a = (int*)malloc(sizeof(int) * n);
		if (nullptr == a)
		{
			perror("malloc fail");
			return;
		}
		capacity = n;
		size = 0;
	}
	void Push(int x)
	{
		//...
		a[size++] = x;
	}
private:		
	// 成员变量
	int* a;
	int size;
	int capacity;
};
int main()
{
	Stack st;
	st.Init();
	st.Push(1);
	st.Push(2);
	st.Push(3);
	return 0;
}

第二种:类声明放在.h文件中,成员函数定义放在.cpp文件中(常用这种)

 头文件中:

//struct Stack无需访问限定符
class Stack//必须有访问限定符,否则报错
{
public:
	// 成员函数
	void Init(int capacity = 4);
	void Push(int x);

private:
	// 成员变量
	int* a;
	int size;
	int capacity;
};

源文件中:

函数名前要加类名 : : (域作用限定符)。

#include "Stack.h"

void Stack::Init(int n)
{
	a = (int*)malloc(sizeof(int) * n);
	if (nullptr == a)
	{
		perror("malloc申请空间失败");
		return;
	}

	capacity = n;
	size = 0;
}

void Stack::Push(int x)
{
	//...
	a[size++] = x;
}

3、访问限定符

在头文件中使用 stuct 定义类:

struct Stack
{
	void Init(int capacity = 4);
	void Push(int x);

	int* a;
	int size;
	int capacity;
};

成功编译: 

C++类与对象(1)—初步认识,C++,c++,开发语言

在头文件中使用 class 定义类:

class Stack
{
	void Init(int capacity = 4);
	void Push(int x);

	int* a;
	int size;
	int capacity;
};

 结果编译后报错如下:

C++类与对象(1)—初步认识,C++,c++,开发语言

我们可以发现成员函数无法访问类的成员,这是因为未加访问限定符的class中默认访问权限为私有private,stuct 默认为公有public。

C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用

 

C++类与对象(1)—初步认识,C++,c++,开发语言 

访问权限符说明:

  • public修饰的成员在类外可以直接被访问
  • protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
  • 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
  • 如果后面没有访问限定符,作用域就到 } 即类结束。
  • class的默认访问权限为private,struct为public(因为struct要兼容C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

 

4、命名规范化 

我们来看这个代码:

class Date
{
public:
	void Init(int year, int month, int day)
	{
		year = year;
		month = month;
		day = day;
	}
private:
	int year;
	int month;
	int day;
};

 在这个代码中,存在一个问题。在Init函数中,你试图将传入的参数赋值给类的成员变量,但是由于参数和成员变量的名称相同,会导致赋值操作无效。

我们可以选择修改参数名或类成员名,比较好的是在成员名前加上符号_ ,这样小改动保证成员名和函数参数名之间的关系。 

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

5、类的实例化

用类类型创建对象的过程,称为类的实例化

  • 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个类,来描述具体学生信息。
  • 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间、存储类成员变量。

类中成员变量是声明,没有分配空间。

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

 只有当我们使用类创建一个对象也就是”类的实例化“时,成员变量才会被分配空间,存储成员变量。

int main()
{
	Date d1;//实例化
	d1.Init(2023, 2, 3);
	return 0;
}

 我们通过下面这段代码看看类实例化之后,有没有占用实际的物理空间。

class A2 {
public:
	void f2() {}
};

int main()
{
	A2 aa1;
	A2 aa2;

	//实例化就能打印地址
	cout << &aa1 << endl;
	cout << &aa2 << endl;

	return 0;
}

通过打印地址可以发现,实例化后变量确实被分配空间用来存储类成员变量了。 

C++类与对象(1)—初步认识,C++,c++,开发语言 

6、计算类对象的大小

类的大小也遵循与结构体一样的计算方式,详细请看这篇文章:结构体内存对齐

7、存储方式

我们先来看下面这段代码:

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:
	int _year; 
	int _month;
	int _day;
};

int main()
{

	Date d1;
	d1.Init(2023, 2, 2);

    //打印d1的大小
	cout << sizeof(d1) << endl;

	return 0;
}

我们由输出结果可知: d1的大小为12字节,由此可以推断出类的对象d1中只存储了成员变量。

C++类与对象(1)—初步认识,C++,c++,开发语言 

那么为什么成员变量在对象中,成员函数不在对象中呢?

因为每个对象成员变量是不一样的,需要独立存储;每个对象调用成员函数是一样的,它们被放到共享公共区域(代码段) 。

class A2 {
public:
	void f2() {}
};

int main()
{
    A2 a;
	cout << sizeof(a) << endl;

	return 0;
}

类中只有成员函数,这样定义的类对象a大小是1字节,这1字节不存储有效数据,是用来占位的,标识对象被实例化定义出来了。 

C++类与对象(1)—初步认识,C++,c++,开发语言

三种类的大小对比

// 类中既有成员变量,又有成员函数
class A1 {
public:
    void f1(){}
private:
    int a;
};

// 类中仅有成员函数
class A2 {
public:
    void f2(){}
};

// 类中什么都没有---空类
class A3
{};
  • 一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐
  • 注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。

 C++类与对象(1)—初步认识,C++,c++,开发语言

三、this指针 

class Date{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
		cout << this << endl;
	}

private:
	int _year; 
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2;
	d1.Init(2022, 2, 2);
	d2.Init(2023, 2, 2);

	return 0;
}
对于上述类,有这样的一个问题:
Date类中有 Init 成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

1、定义 

C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏
的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”
的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编
译器自动完成。
如下图所示: C++类与对象(1)—初步认识,C++,c++,开发语言

我们在初始化Init函数中打印this指针,看看this指针有没有发挥作用。

class Date
{
public:
	void Init(int year, int month, int day)
	{
		cout << this << endl;
    //可以显式使用this,不能显式定义this
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2;
	d1.Init(2022, 2, 2);
	d2.Init(2023, 2, 2);

	return 0;
}

 输出了两个地址,我们通过调试检查一下这两个地址是不是对象d1和d2的地址。

C++类与对象(1)—初步认识,C++,c++,开发语言 

在调试中地址如下,上下两幅图对比可以得知,每次初始化时,this指针会指向参数的地址。

C++类与对象(1)—初步认识,C++,c++,开发语言

在实际中类的成员函数一般不需要加this指针。 

2、存储位置

this存在哪里?

栈,因为他是隐含形参,vs下在ecx寄存器中。

 通过之前计算类的对象大小不包括this,所以this在栈上,它是一个隐含的形参。

 3、辨析

class Date
{
public:
	void Init(int year, int month, int day)
	{
		cout << this << endl;
    //可以显式使用this,不能显式定义this
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	void func()
	{
		cout << "func()" << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date* ptr = nullptr;
    ptr->func();

	return 0;
}

程序正常运行: 

C++类与对象(1)—初步认识,C++,c++,开发语言 

如果调用这句呢? 

ptr->Init(2022, 2, 2);

结果运行崩溃:

 C++类与对象(1)—初步认识,C++,c++,开发语言

下面来解释这两种情况: 

  1. ptr->func()这行代码尝试通过空指针ptr调用成员函数func()。虽然ptr是空指针,但是在这种情况下,由于func()函数没有使用或修改任何成员变量,它可以被静态调用。这意味着它不依赖于具体的对象实例,不需要借助this指针,因此不会引发崩溃。

  2. ptr->Init(2022, 2, 2)这行代码尝试通过空指针ptr调用成员函数Init()。由于Init()函数内部使用了this指针来访问对象的成员变量,而空指针没有有效的对象实例,对空指针的解引用无效,因此在访问this->_yearthis->_monththis->_day时会导致程序崩溃。

同理这段代码也可以正常运行: 

(*ptr).func();

C++类与对象(1)—初步认识,C++,c++,开发语言 

 四、封装好处

C++中: 

  1. 数据和方法都封装到类里面
  2. 控制访问方式,愿意给你访问公有,不愿意给你访问私有。

C语言中: 

  1. 数据和方法是分离的
  2. 数据访问控制是自由的,不受限制的

 C++实现栈:

typedef int DataType;
class Stack
{
public:
	void Init()
	{
		_array = (DataType*)malloc(sizeof(DataType) * 3);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		_capacity = 3;
		_size = 0;
	}
	void Push(DataType data)
	{
		CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	void Pop()
	{
		if (Empty())
			return;
		_size--;
	}
	
    DataType Top() { return _array[_size - 1]; }
	int Empty() { return 0 == _size; }
	int Size() { return _size; }
	
    void Destroy()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	void CheckCapacity()
	{
		if (_size == _capacity)
		{
			int newcapacity = _capacity * 2;
			DataType* temp = (DataType*)realloc(_array, newcapacity *
				sizeof(DataType));
			if (temp == nullptr)
			{
				perror("realloc申请空间失败!!!");
				return;
			}
			_array = temp;
			_capacity = newcapacity;
		}
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
}; ​
C++中通过类可以将数据 以及 操作数据的方法进行完美结合,通过访问权限可以控制那些方法在类外可以被调用,即封装,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。而且每个方法不需要传递Stack*的参数了,编译器编译之后该参数会自动还原,即C++中 Stack * 参数是编译器维护的,C语言中需用用户自己维护。

下一篇:构造函数&析构函数

C++类与对象(2)—构造函数&析构函数文章来源地址https://www.toymoban.com/news/detail-752576.html

到了这里,关于C++类与对象(1)—初步认识的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java——面向对象的初步认识

    目录 一.什么是面向对象 二.面向对象与面向过程 1. 传统洗衣服过程(面向过程) 2. 现代洗衣服过程(面向对象) Java是一门纯面向对象的语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。 面向对象是解决问题的一种思想,主要依靠对象之间的交互完成

    2024年04月13日
    浏览(40)
  • 【我与java的成长记】之面向对象的初步认识

    能看懂文字就能明白系列 C语言笔记传送门 🌟 个人主页 :古德猫宁- 本节目标: 了解什么是面向对象,与面向过程的区别 掌握类的定义方式以及对象的实例化 掌握类中的成员变量和成员方法的使用 大家都知道Java是一种面向对象的开发语言,那么什么是面向对象呢? 所谓

    2024年02月04日
    浏览(39)
  • 【C++】初步认识模板

    🏖️作者:@malloc不出对象 ⛺专栏:C++的学习之路 👦个人简介:一名双非本科院校大二在读的科班编程菜鸟,努力编程只为赶上各位大佬的步伐🙈🙈 本篇文章我们讲解的是模板,它极大的节省了我们成本去构造多份差不多的代码,它是复用性很强的一种手段,下面就让我

    2024年02月11日
    浏览(36)
  • 初步认识C语言(二)

    目录 7. 选择语句  8. 循环语句  9. 函数 10.数组 10.1 数组定义 10.2 数组的下标  10.3 数组的使用  11. 操作符 12. 常见 12.1 typedef 12.2 static  12.2.1 修饰局部变量  12.2.2 修饰全局变量  12.2.3 修饰函数 ​编辑 13. #define 定义常量和宏  14. 指针 14.1 内存  14.2 指针

    2024年02月12日
    浏览(44)
  • 0821|C++day1 初步认识C++

    1)创建文件 创建文件时,文件的路径一定是全英文 2)修改编码 工具---选项---行为---默认编码:system C++又叫C plus plus,C++是对C的扩充,几乎支持所有的C语言语法 C语言:面向过程语言  ------偏重解决问题的步骤 C++:面向对象语言   ------求解的方法 面向对象的三大特征

    2024年02月11日
    浏览(37)
  • 【c++ • STL】初步认识什么是 STL 标准库

    🚀 个人简介:CSDN「 博客新星 」TOP 10 , C/C++ 领域新星创作者 💟 作    者: 锡兰_CC ❣️ 📝 专    栏: 从零开始的 c++ 之旅 🌈 若有帮助,还请 关注➕点赞➕收藏 ,不行的话我再努努力💪💪💪    本文我们将初步认识 STL,了解 STL 的历史,STL 的不同实现版本,以及

    2024年02月05日
    浏览(36)
  • C++初阶学习第三弹——类与对象(上)——初始类与对象

    前言: 在前面,我们已经初步学习了C++的一些基本语法,比如内敛函数、函数重载、缺省参数、引用等等,接下来我们就将正式步入C++的神圣殿堂,首先,先给你找个对象 目录 一、类与对象是什么? 二、类的各部分组成 1、类的定义 2、类的访问限定符及封装 3、类的作用域

    2024年04月26日
    浏览(50)
  • c++类与对象

    🐶博主主页: @ᰔᩚ. 一怀明月ꦿ  ❤️‍🔥 专栏系列: 线性代数,C初学者入门训练,题解C,C的使用文章 🔥 座右铭: “不要等到什么都没有了,才下定决心去做” 🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀  目录 🐰类与对象 🌸

    2023年04月08日
    浏览(45)
  • C++类与对象(下)

    您好这里是limou3434的博文,感兴趣可以看看我的其他博文系列。 这一部分是对C++类的一些补充:初始化列表、友元、内部类。 在给对象进行初始化的时候,如果选择函数体内进行初始化是一件很麻烦的事情。 但是这样写是没有办法过的,要成功运行的话只能写一个默认构造

    2024年02月11日
    浏览(43)
  • 【C++】类与对象(上)

    之前的文章中讲解了,什么是类、类的实例化,以及封装的意义,若仍有不理解的部分可以移步上一篇文章  【C++】类与对象(引入) 目录 系列文章 1.默认成员函数 2.构造函数 2.1定义 2.2特性 2.2.1重载构造函数 2.2.2与缺省参数混合使用 2.2.3默认构造函数 3.析构函数 3.1定义

    2023年04月15日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包