从零开学C++:类和对象(上)

发布于:2024-07-11 ⋅ 阅读:(23) ⋅ 点赞:(0)

引言:在学习了C++的入门级知识之后,现在就让我们一起进入类和对象的学习吧,该知识点我将分为上,中,下三个部分对其进行讲解。

更多有关C语言数据结构的知识详解可前往个人主页:计信猫

目录

一,类的引入

二,类的定义

1,类定义的格式

2,类定义的两种方式

三,类的访问

四,类大小的计算

五,this指针


一,类的引入

        在C语言当中,我们定义一个结构体的时候,里边的成员只可以为变量,不可以为函数,但是在C++中,我们会发现在结构体struct当中,我们还可以定义函数。就比如以数据结构初阶知识——栈为例子:

struct Stack
{
	//定义成员函数
	void StackInit(Stack* st)
	{
		st->_a = NULL;
		st->_capacity = st->_top = 0;
	}
	int* _a;
	int _top;
	int _capacity;
};

        而在C++中,我们更习惯使用的类定义关键字class。 

二,类的定义

1,类定义的格式

        当我们想要定义一个时,我们就可以使用关键字class来对类进行定义,而格式其实也跟C语言中的struct十分相似,如下:

class classname//classname表示类的名称
{
	//成员变量,成员函数
};

2,类定义的两种方式

        在定义成员函数时,第一种方法,我们可以成员函数的声明和定义都放在里边,如下所示:

class Person
{
	//将成员函数的声明和定义放在一起
	void PersonInfo(Person* p)
	{
		cout << p->_name << ' ' << p->_age << ' ' << p->_number << endl;
	}
	char* _name;
	int _age;
	int _number;
};

        第二种方式在工作当中就会被经常使用到,当函数的声明和定义分别在.h.cpp为后缀的两个文件当中时,我们就需要用到之前所学到的域作用限定符“::”了。

//.h文件当中存放函数的声明
class Person
{
	//将成员函数的声明和定义放在一起
	void PersonInfo(Person* p);
	char* _name;
	int _age;
	int _number;
};
//.cpp文件当中存放函数的定义
void Person::PersonInfo(Person* p)
{
	cout << p->_name << ' ' << p->_age << ' ' << p->_number << endl;
}

三,类的访问

         在的成员中,其实它们被分为了三类:public,private,protectedpublic修饰的成员在类之外也可以被访问privateprotected修饰的成员在之外就不能被访问了。它们的限定区域为从该访问限定符开始到下一个访问限定符或者“}”结束。其中class定义的类默认都为privatestruct定义的类默认都为public

        那么我们就可以定义一个的来进行举例说明:

class Date
{
public:
	//可以在类之外被访问
	void showdate()
	{
		//函数定义
	}
private:
	//只可以在类之内被访问
	int _year;
	int _month;
	int _date;
};

四,类大小的计算

        首先我们需要明白一个知识点,那就是在我们将一个类实例化,也就是创建了一个类的对象的时候,中的不同的成员类型都会在内存当中开辟不同的空间,而成员函数并不会开辟空间,它只会存在于一个内存当中公共位置并不是说创建多少个对象,就开辟多少份空间用于储存成员函数。 

        那当我们想要计算一个的字节大小的时候,其实非常简单,因为类的大小的计算也同样遵循我们之前所学到的结构体内存对齐的知识点。如果现在还不清楚或者有遗忘的话,给你一个传送门:结构体内存对齐,赶快去学习吧!!

        在这里我们粗略地讲一下结构体内存对齐存在的原因:在机器读取数据时,都是整数倍的位置开始读,并且读的字节个数固定(与机器有关),若不进行结构体内存对齐,就有可能导致一次取数据取到不同的变量类型

        而当没有成员变量或者只有成员函数的时候,此时的大小就为一个字节(纯粹是为了表示这个类的存在,一个占位标识而已)。

五,this指针

        this指针其实是C++里边的一个隐含关键字,我们可以举出如下例子来讲解:

class Date
{	
public:
	void Print()
	{
		cout << _year << ' ' << _month << ' ' << _date << endl;
	}
	int _year;
	int _month;
	int _date;
};
int main()
{
	Date d1;
	d1.Print();
}

        当我们定义一个名为Date,并且在main函数中调用里边的成员函数时,在程序运行时其实整个代码就会变成下面这样:

class Date
{	
public:
	void Print(Date* const this)
	{
		cout << this->_year << ' ' << this->_month << ' ' << this->_date << endl;
	}
	int _year;
	int _month;
	int _date;
};
int main()
{
	Date d1;
	d1.Print(&d1);
}

        怎么样,看到this指针的身影了吗?所以说,this指针其实就是一个表示类的对象的地址的指针,它一般会由编译器自己写上,当然,也可以被我们写在函数定义里边,但是声明上不能写。 

        那让我们看一个题目,加深我们对前边知识的理解:

class Date
{	
public:
	void Print()
	{
		cout << Print() << endl;
	}
	int _year;
	int _month;
	int _date;
};
int main()
{
	Date* p = nullptr;
	p->Print();
}

        那么这段代码在运行的时候会发生错误吗?答案是不会,因为此时this指针的值就是p,也就是nullptr,而Print()函数存在于一个公共区域,不需要对其进行解引用操作,那么代码就会正常运行。

        可一旦我们使用p指针进行访问成员类型的操作的时候,那么代码就会产生错误,因为此时我们就涉及到了对空指针nullptr解引用了。