目录

C修炼类和对象上

C++修炼:类和对象(上)

Hello大家好!很高兴我们又见面啦!给生活添点passion,开始今天的编程之路!

https://i-blog.csdnimg.cn/direct/91bfeb2bb1414a2ebf09cbc4f9706779.gif

我的博客:

我的专栏: 、 、 、

欢迎点赞,关注!

我们先来定义一个类:

#include<iostream>
using namespace std;
class TEST
{
public:
	//成员函数
	void test()
	{
		return;
	}
private:
	//成员变量
	int _a;
	int _b;
};
int main()
{
	return 0;
}

现在我们来剖析一下这串代码。 class为类的关键字,TEST为类的名字。{}中的为类的主体。

其实 类就是c语言里面结构体的升级版 。但需要注意的是,C++兼容C的定义方式,所以在c++中也可以定义struct结构体。并且在c++中,我们不用typedef了,举个例子:

typedef struct ListNodeC
{
 struct ListNodeC* next;
 int val;
}LTNode;

这是我们在学习链表是定义的节点。我们传参时都是LTNode* ph传入头结点。但是在 C++ 中,我们 不需要typedef 了,直接拿 listNodeC 就可以代表这个节点。

我们可以把上面的代码写成这样:

struct ListNodeC
{
 struct ListNodeC* next;
 int val;
}LTNode;

这是结构体的第一点升级,第二点升级就是在 C++中结构体也可以定义成员函数。

在C++中,虽然可以使用struct,但还是推荐使用class定义类。

类里面成员变量的命名大多是_加变量名。 当然了,这个还是要根据公司规定以及个人习惯来调整的。

类中的成员函数默认为内联

在上面的代码中我们并没有介绍public和private。 其实public和private是访问限定符。在public后面的成员函数和成员变量可以直接在类的外部使用。private后面的成员函数和成员变量不能被直接使用。

通常我们把成员函数定义为public,把成员变量定义为private。

https://i-blog.csdnimg.cn/direct/d2379c2f6a674d50b9ac885444dcfa06.png

类的正常使用:

#include<iostream>
using namespace std;
class TEST
{
public:
	//成员函数
	int test(int a,int b)
	{
		return a+b;
	}
private:
	//成员变量
	int _a;
	int _b;
};
int main()
{
	TEST A;
	int c = 10;int d = 20;
	cout << A.test(c, d) << endl;
	return 0;
}

类定义了一个新的作用域,类的所有成员函数都在类的作用域中。在类体外定义成员时,需要使用类域名::来访问成员。

如果不指定类域的话,在定义函数时,程序在全局域找不到函数的声明就会报错。 编译器不会主动去类域中寻找函数定义。

#include<iostream>
using namespace std;
class TEST
{
public:
	//成员函数声明
	int test(int a, int b);
	
private:
	//成员变量
	int _a;
	int _b;
};
int TEST::test(int a, int b)
{
	return a + b;
}
int main()
{
	TEST A;
	
	int c = 10;int d = 20;
	cout << A.test(c, d) << endl;
	return 0;
}

用类的类型在物理内存中创建对象的过程,叫做实例化对象。

例如上面代码的TEST A;这一句就是实例化出了对象A。在这一句之前我们只是定义了类,但并没有给类里面任何一个成员函数和成员变量分配空间。 没有实例化出的对象不能存储数据。

也就是说,在定义时int _a根本没有给_a这个变量开空间,这只是声明了_a这个变量。

对象的大小只包含成员变量的大小,成员函数不占内存空间。 打个比方,我现在实例化出了两个类,分别为A,B。A和B的成员变量是不同的,地址是不同的。但如果访问这两个类的成员函数,他们都会链接到一个地址。所以说我们sizeof(类对象)只用统计成员变量占用的空间。

成员变量占用的空间也符合内存对齐规则。之前在C语言结构体部分说过了,这里就不过多赘述了。

#include<iostream>
using namespace std;
class Date
{
public:
	// void Init(Date* const this, int year, int month, int day)
	void Init(int year, int month, int day)
	{
		// this->_year = year;
		_year = year;
		this->_month = month;
		this->_day = day;
	}
	void Print()
		 {
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	// 这⾥只是声明,没有开空间 
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date A;
	
	return 0;
}

我们来看这串代码:Init这个函数在调用时正常的语句应该是_year = year;,可是大家想一个问题,编译器是怎么找到我们的成员变量_year的?

其实,成员函数在传参时都有一个类的指针类型的 this指针 。这个this指针编译器不会显示出来,但实际上他是存在的。我们看上边这串代码,如果再函数调用赋值的时候,我们可以手动把this指针加上去,这样其实并不会报错。这就说明这个this指针是真实存在的。

另外需要注意一点,this指针其实存放在栈区,而不是对象里面。

接着我们来看个有趣的题目:

下面程序编译运行结果是()

A、编译报错  B、运行崩溃  C、正常运行

#include<iostream>
using namespace std;
class A
{
public:
 void Print()
 {
 cout << "A::Print()" << endl;
 }
private:
 int _a;
};
int main()
{
 A* p = nullptr;
 p->Print();
 return 0;
}
#include<iostream>
using namespace std;
class A
{
public:
 void Print()
 {
 cout << "A::Print()" << endl;
 cout << _a << endl;
 }
private:
 int _a;
};
int main()
{
 A* p = nullptr;
 p->Print();
 return 0;
}

这两串代码运行的结果并不相同。 第一个是正常运行,第二个是运行崩溃 。首先我们应该排除的是A选项。因为不管是C语言中还是C++中,解引用空指针并不会编译报错,只会运行崩溃。

我们再来分析问什么 第一个是正常运行,第二个是运行崩溃。

在第一个程序中我们并没有涉及到开空间的问题。还记得前面说过的吗,成员函数不会占用物理内存,只有成员变量会。我们实例出的类是nullptr说明根本就没开空间。但是第一个程序是不需要访问成员变量的,所以不开空间也没有报错。而第二个程序访问了没开空间的成员变量,所以运行崩溃了。

好了,今天的内容就分享到这,我们下期再见!