首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++ 篇 类和对象(1)万能工具怎么用?

C++ 篇 类和对象(1)万能工具怎么用?

作者头像
胖咕噜的稞达鸭
发布2025-10-22 14:57:02
发布2025-10-22 14:57:02
2900
代码可运行
举报
文章被收录于专栏:C++初阶高阶C++初阶高阶
运行总次数:0
代码可运行

一.类的定义

  1. 类定义格式
  • class为定义类的关键字,Stack为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数
代码语言:javascript
代码运行次数:0
运行
复制
#include<iostream>
#include<assert.h>
using namespace std;

//class 定义类的关键字,stack 是类的名字,{ }中为类的主体
class Stack
{
public:
	//成员函数
	void Init(int n = 4)
	{
		array = (int*)malloc(sizeof(int) * n);
		if (nullptr == array)
		{
			perror("malloc申请空间失败");
				return;
		}

		capacity = n;
		top = 0;
	}

	void Push(int x)
	{
		//扩容
		array[top++] = x;
	}

	int Top()
	{
		assert(top > 0);

		return array[top - 1];
	}

	void Destroy()
	{
		free(array);
		array = nullptr;
		top = capacity = 0;
	}

private:
	//成员变量    private表示其一下的内容不可修改
	int* array;//栈中的数组
	size_t capacity;
	size_t top;
};//这个分号不可省略

int main()//没有返回值也不可写void!!!
{
	Stack st;//类型可以访问 //st是栈对象
	st.Init();//通过对象成员函数()调用,编译器会隐式传递this指针(指回当前对象),让成员函数能访问对象的私有成员
	st.Push(1);
	st.Push(2);//栈顶为2,栈底为1

	cout << st.Top() << endl;//  << 输出  通过cout输出到控制台

	st.Destroy();

	return 0;
}
  • 为了区分成员变量,一般习惯上成员变量会加一个特殊标识,如成员变量前面或者后面加_或者_m开头,注意C++中这个并不是强制的。
代码语言:javascript
代码运行次数:0
运行
复制
class Date
{
public:
	//成员函数
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	//成员变量
	//加一个特殊标记,_或者_m开头
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d;
	d.Init(2025, 9, 18);

	return 0;
}
  • C++中struct也可以定义类,C++兼容C中struct的用法,同时struct升级成了类,明显的变化是struct中可以定义函数,一般情况下我们还是推荐用class定义类。
代码语言:javascript
代码运行次数:0
运行
复制
typedef int STDataType;
typedef struct ListNode
{
	int val;
	struct ListNode* next;
}LTnode;
代码语言:javascript
代码运行次数:0
运行
复制
#include<iostream>
using namespace std;

 struct ListNodeCPP
{
	 //成员函数
	 void Init(int x)
	 {
		 next = nullptr;
		 val = x;
	 }
	 //成员变量
	 ListNodeCPP* next;
	 int val;
};

 int main()
 {
	 return 0;
 }

定义在类面前的成员函数默认为inline。

  1. 访问限定符

三种

public

访问

private

限定符

protected

public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能被直接访问,private和protected是一样的。

访问权限作用域从该访问限定符开始的位置到下一个访问限定符的出现时为止,如果后面没有访问 限定符,作用域到}就结束。

class定义成员没有被访问限定符修饰的时候默认为private,struct默认为public。

  1. 类域
代码语言:javascript
代码运行次数:0
运行
复制
#include<iostream>
using namespace std;
class Stack
{
public:
	// 成员函数
	void Init(int n = 4);
private:
	// 成员变量
	int* array;
	size_t capacity;
	size_t top;
};
// 声明和定义分离,需要指定类域
void Stack::Init(int n)//说明Init不是一个全局函数,是类的成员函数
{
	array = (int*)malloc(sizeof(int) * n);
	if (nullptr == array)
	{
		perror("malloc申请空间失败");
		return;
	}
	capacity = n;
	top = 0;
}
int main()
{
	Stack st;
	st.Init();
	return 0;
}

面试题插入:说出声明和定义的区别: 声明就是告诉变量的类型;定义要开空间。

二.实例化

  • 什么是实例化 类是对象进行一种抽象描述,是一个模型一样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,用类实例化出对象时,才会分配空间。类和实例化对象的关系相当于一张图纸和许多建筑的关系。
  • 对象大小 Date实例化d1和d2两个对象,d1和d2都有各自独立的成员变量_year/_month/_day存储各自的数据,但是d1和d2的成员函数Init/Print指针却是一样的,存储在对象中就浪费了。 调用函数被编译成汇编指令[call地址],其实编译器在编译链接时,就要找到函数的地址,不是在运行时找,只有动态多态是在运行时找,就需要存储函数地址。
  • 内存对齐规则
  • [1 ] 第一个成员在与结构体偏移量为0的地址处,
  • [2 ] 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
  • [ 3] 注意:对齐数=编译器默认的一个对齐数与该成员大小的较小值。
  • [ 4] VS中默认的对齐数为8
  • [ 5] 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
  • [ 6] 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

下面给三个例子算一下实例化对象分别有多大?

代码语言:javascript
代码运行次数:0
运行
复制
#include<iostream>
using namespace std;// 计算一下A / B / C实例化的对象是多大?
class A 
{ 
public:
	void Print()
	{ 
		cout << _ch << endl;
	}
private:
	char _ch; int _i;
};
class B 
{
public:
	void Print() 
	{
		//...
	}
};
class C
{};
int main()
{
	A a;
	B b;
	C c;
	cout << sizeof(a) << endl;
	cout << sizeof(b) << endl;
	cout << sizeof(c) << endl; //1B和C大小一致,虽然没有成员变量的类,但是它存在就要开空间,给一个字节,纯粹就是为了占位标记
	return 0;
}

三.this指针

C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理),但是可以在函数体内显示使用this指针。

代码语言:javascript
代码运行次数:0
运行
复制
#include<iostream>
using namespace std;
class Date
{
public:
	// void Init(Date* const this, int year, int month, int day)
	//所有成员函数都会增加隐含的this指针
	void Init(int year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	// void Print(Date* const this)
	void Print()
	{
		cout << this->_year << "/" << this->_month << "/" << _day << endl;
	}

private:
	// 这里只是声明,没有开空间
	int _year;
	int _month;
	int _day;
};

int main()
{
	// Date类实例化出对象d1和d2
	Date d1;
	Date d2;

	// d1.Init(&d1, 2024, 3, 31);
	d1.Init(2024, 3, 31);
	// d1.Print(&d1);
	d1.Print();
	
	// d2.Init(&d2, 2024, 7, 5);
	d2.Init(2024, 7, 5);
	// d2.Print(&d2);
	d2.Print();

	//不可以写成d2.Print(d2);//但是可以在函数体内写
	return 0;
}

下面以两个选择题结束今天的学习 1.这段代码会编译运行结果是()

代码语言:javascript
代码运行次数:0
运行
复制
#include<iostream>
using namespace std;

class A
{
public:
	void Print()
	{
		//cout << this << endl;
		cout << "A::Print()" << endl;
	}
private:
	int _a;
};

int main()
{
	A* p = nullptr;
	            // mov ecx  p
	p->Print(); // call  地址
	//p->_a = 1;

	return 0;
}

2.下面程序编译运行的结果是编译报错为什么?

代码语言:javascript
代码运行次数:0
运行
复制
#include<iostream>
using namespace std;

class A
{
public:
	void Print()
	{
		cout << "A::Print()" << endl;
		cout << _a << endl;//_a需要存在对象A里面,这里访问_a是通过this来访问的(相当于解引用)
	}
private:
	int _a;
};

int main()
{
	A* p = nullptr;
	            // mov ecx  p
	p->Print(); // call  地址
	//调用Print函数传参,把P传给ecx,call位置是地址,地址不存对象P里面,不存在解引用
	//不会从对象里面找,地址是在编译的时候就确定的

	return 0;
}

引用和指针的区别:

指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-09-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.类的定义
  • 二.实例化
  • 三.this指针
  • 引用和指针的区别:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档