C++之类(持续更新)

1、类的基础知识点

1.1、类和对象

和C中的结构体不同,在C++类中不仅可以定义变量,也可以定义函数。【在C++结构体中也可以定义变量和函数,但是一般情况下都使用类】。

类的成员属性默认都是private;结构体的成员属性默认都是public。

cpp 复制代码
class student
{
public:
	// 共有成员(外部接口,可被使用该类的所有代码所使用的)
	student();
	~student();
	void set_age(int age_t);
private:
	// 私有成员(只允许本类中的函数访问,而类外部的任何函数都不允许访问)
	char name[50];
	int age;
protected:
	// 保护成员(与private类似,差别表现在继承与派生时)
};

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

1.2、类中成员函数定义

(1)声明和定义都放在类体中

cpp 复制代码
// .h文件中
class student
{
public:
	// 共有成员(外部接口,可被使用该类的所有代码所使用的)
	student();
	~student();
	void set_age(int age_t)
    {
        age = age_t;
    }
private:
	// 私有成员(只允许本类中的函数访问,而类外部的任何函数都不允许访问)
	char name[50];
	int age;
protected:
	// 保护成员(与private类似,差别表现在继承与派生时)
};

(2)声明和定义分离

cpp 复制代码
// .h文件中
class student
{
public:
	// 共有成员(外部接口,可被使用该类的所有代码所使用的)
	student();
	~student();
	void set_age(int age_t);
private:
	// 私有成员(只允许本类中的函数访问,而类外部的任何函数都不允许访问)
	char name[50];
	int age;
protected:
	// 保护成员(与private类似,差别表现在继承与派生时)
};
cpp 复制代码
// .cpp文件中
void student::set_age(int age_t)
{
	age = age_t;
}

1.3、类的作用域

C++类重新定义了一个作用域,类的所有成员都在类的作用域中。在类外使用成员时,需要使用 **::(作用域解析符)**来指明成员属于哪个类。

1.4、实例化

用类去创建对象的过程,称为类的实例化。类只声明了类有哪些成员,而并没有为成员分配内存空间。一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量

类是对象的抽象和概括,而对象是类的具体和实例。

1.5、类对象的存储方式

C++程序占用的内存通常分为四个区:

代码区(code area):存放着程序的二进制代码,由操作系统管理。

全局区(static area):存放全局变量,静态变量,以及常量(字符常量和const修饰的全局变量)。

栈区(stack area):存放所有的局部变量,其空间分配释放由编译器管理,当函数结束,局部变量自动被释放。

堆区(heap area):存放所有动态开辟的变量,其空间分配释放由程序员管理。

类对象存储如下:

在类定义时:

类的成员函数是被放在代码区。

类的静态成员变量是存储在静态区的,即实例化的对象并不包括静态变量的创建。

类的静态成员变量,在类的实例化过程中才在栈区或者堆区为其分配内存,是为每个对象生成一个拷贝,所以它是属于对象的。

cpp 复制代码
#include <iostream>
using namespace std;

class student_1
{
public:
	void set_age(int age_t);
private:
	char name[50];
	int age;
	static char aa[8];
}std_1;

class student_2
{
public:

private:
	char name[50];
	int age;
}std_2;

class student_3
{
}std_3;

int main(int argc, char argv[])
{
	cout << "  " << sizeof(std_1) << endl;
	cout << "  " << sizeof(std_2) << endl;
	cout << "  " << sizeof(std_3) << endl;
	return 0;
}

输出:

cpp 复制代码
56
56
1

结论:

一个类的大小,实际就是该类中"成员变量"之和,当然也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。

注意:

这里的成员变量之和并不是简单的字节数相加,而是还要遵循内存对齐规则。

1.6、this指针

cpp 复制代码
#include <iostream>
using namespace std;

class student
{
public:
	void set_id(int grade_id__t, int class_id_t);
	void display_id_0()
	{
		cout << "grade_id: " << grade_id << ", class_id: " << class_id << endl;
	}
	void display_id_1()
	{
		cout << "grade_id: " << this->grade_id << ", class_id: " << this->class_id << endl;
	}
private:
	char name[50];
	int age;
	int grade_id;
	int class_id;
};

void student::set_id(int grade_id__t, int class_id_t)
{
	grade_id = grade_id__t;
	class_id = class_id_t;
}

int main(int argc, char argv[])
{
	student std_1, std_2;
	std_1.set_id(10, 11);
	std_2.set_id(101, 34);
	std_1.display_id_0();
	std_1.display_id_1();
	std_2.display_id_0();
	std_2.display_id_1();

	return 0;
}

结果为:

cpp 复制代码
grade_id: 10, class_id: 11
grade_id: 10, class_id: 11
grade_id: 101, class_id: 34
grade_id: 101, class_id: 34

问题一:

对于上述程序,std_1和std_2各自有不同的内存空间,而成员函数set_id中却并没有指定要对哪一个对象的成员进行操作,那么当std_1调用时函数是如何知道操作的对象是哪一个呢?

答:

C++中通过引入this指针解决该问题,即:C++编译器给每个"非静态的成员函数"增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

this指针的特性:

this指针的类型:类的类型* const,this在函数体内不可修改。

只能在"成员函数"的内部使用。

this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针。

this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。

问题二:

this指针的存储位置在哪里?

答:

临时变量都是存储在栈上的,因此this指针作为形参,存储在栈区。

问题三:

this指针可以为空指针吗?

答:

this指针可以为空指针,但切忌通过nullptr去访问指向的数据。

cpp 复制代码
#include <iostream>
using namespace std;

class student
{
public:
	void set_id(int grade_id__t, int class_id_t);
	void display_id()
	{
		cout << "grade_id: " << grade_id << ", class_id: " << class_id << endl;
	}
	void display()
	{
		cout << "grade_id and class_id" << endl;
	}
private:
	char name[50];
	int age;
	int grade_id;
	int class_id;
};

void student::set_id(int grade_id__t, int class_id_t)
{
	grade_id = grade_id__t;
	class_id = class_id_t;
}

int main(int argc, char argv[])
{
	student *std_1 = nullptr;
	std_1->display();         // 执行成功
	std_1->display_id();      // 执行失败
	return 0;
}

成员函数display()执行成功,而成员函数display_id()执行失败。首先nullptr地址我们是没有访问权限的,非法访问会使程序崩溃。

display()执行成功,因为访问的是成员函数,成员函数不在对象内,就不会对指针解引用,std_1->的作用仅仅是指明了函数的类域,而函数内也没有使用到this指针,所以不会报错。

display_id()执行失败,是因为在打印的时候调用了成员变量grade_id和class_id,而std_1又指向了nullptr,相当于访问了nullptr地址处的数据,因此程序崩溃。

2、

3、

4、

5、

End、结语

感谢参考的文档;参考的文档太多,不做一一列举。

感谢大家提供的建议;

相关推荐
记录成长java29 分钟前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山29 分钟前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
青花瓷32 分钟前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode
睡觉谁叫~~~33 分钟前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust
音徽编程34 分钟前
Rust异步运行时框架tokio保姆级教程
开发语言·网络·rust
观音山保我别报错34 分钟前
C语言扫雷小游戏
c语言·开发语言·算法
程序媛小果1 小时前
基于java+SpringBoot+Vue的旅游管理系统设计与实现
java·vue.js·spring boot
小屁孩大帅-杨一凡1 小时前
java后端请求想接收多个对象入参的数据
java·开发语言
m0_656974742 小时前
C#中的集合类及其使用
开发语言·c#
java1234_小锋2 小时前
使用 RabbitMQ 有什么好处?
java·开发语言