C++之类(持续更新)

1、类的基础知识点

1.1、类和对象

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

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

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

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

1.2、类中成员函数定义

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

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

(2)声明和定义分离

// .h文件中
class student
{
public:
	// 共有成员(外部接口,可被使用该类的所有代码所使用的)
	student();
	~student();
	void set_age(int age_t);
private:
	// 私有成员(只允许本类中的函数访问,而类外部的任何函数都不允许访问)
	char name[50];
	int age;
protected:
	// 保护成员(与private类似,差别表现在继承与派生时)
};
// .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):存放所有动态开辟的变量,其空间分配释放由程序员管理。

类对象存储如下:

在类定义时:

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

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

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

#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;
}

输出:

56
56
1

结论:

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

注意:

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

1.6、this指针


#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;
}

结果为:

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去访问指向的数据。


#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、结语

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

感谢大家提供的建议;

相关推荐

  1. 算法竞赛总结(C++) 持续更新

    2024-03-17 11:38:02       170 阅读
  2. c++刷题leetcode常见报错(持续更新

    2024-03-17 11:38:02       66 阅读
  3. C++音视频开发技巧汇总(持续更新

    2024-03-17 11:38:02       56 阅读
  4. Python基础(持续更新)

    2024-03-17 11:38:02       46 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-17 11:38:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-17 11:38:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-17 11:38:02       87 阅读
  4. Python语言-面向对象

    2024-03-17 11:38:02       97 阅读

热门阅读

  1. 码云使用 创建项目

    2024-03-17 11:38:02       45 阅读
  2. 比特币,区块链及相关概念简介(三)

    2024-03-17 11:38:02       44 阅读
  3. 容器只适用于微服务吗?

    2024-03-17 11:38:02       37 阅读
  4. docker的基本知识点

    2024-03-17 11:38:02       39 阅读
  5. stm32_f103c8点亮led(01)

    2024-03-17 11:38:02       43 阅读
  6. 1.AD域控如何强制删除不可以用域控服务器

    2024-03-17 11:38:02       38 阅读
  7. 如何调整服务器系统时间

    2024-03-17 11:38:02       42 阅读