栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++ 类(初识)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++ 类(初识)

一、类的引入

在C语言中,struct 只能定义变量

比如,在C语言中定义一个栈,我们最关注的是这些函数的过程的实现。

struct Stack
{
	int* a;
	int top;
	int capacity;
};

void Stack_Init(struct Stack* ps);
void Stack_Push(struct Stack* ps, int x);
void Stack_Pop(struct Stack* ps);
//......

而C++中不仅兼容 C struct 的用法,同时将 struct 升级成了类,也就是说C++对 struct 进行了升级,它不仅可以定义变量,还能定义函数。

struct Stack
{
	void Init()
	{
		//...
	}

	void Push(int x)
	{
		//...
	}

	void Pop()
	{
		//...
	}

	int* a;
	int top;
	int capacity;
};

然后就可以直接这样调用这个函数

int main()
{
	Stack st;

	st.Init();
	st.Push(1);
	st.Pop();

	return 0;
}

同时在C++中,类名就是类型,可以直接这样定义不需要 typedef

int main()
{
	struct Stack st1;  //C
	Stack st2;         //C++
	return 0;
}

但是C++中定义类还是更喜欢用 class


二、类的访问限定符
访问限定符:public(公有)protected(保护)private (私有)

public  (公有) 就是在类里面可以访问,类外面也可以访问

private (私有) 就是在类里面可以访问,类外面不能访问

现阶段 protected 和 private 类似


如果把刚才 struct 定义的东西改成 class

  • class Stack
    {
    	void Init()
    	{
    		//...
    	}
    
    	void Push(int x)
    	{
    		//...
    	}
    
    	void Pop()
    	{
    		//...
    	}
    
    	int* a;
    	int top;
    	int capacity;
    };
    
    int main()
    {
    	Stack st;
    
    	st.Init();
    	st.Push(1);
    	st.Pop();
    
    	return 0;
    }

然后编译一下,就会发现它报错了,说 无法访问 私有。

是因为我们没有给 class 访问限定符,class 默认访问权限为 private,而 struct 为 public(因为 struct 要兼容C)


 如果是想给别人用的就设置成 公有的

class Stack
{
public:
	void Init()
	{
		//...
	}

	void Push(int x)
	{
		//...
	}

	void Pop()
	{
		//...
	}

直到遇到下一个访问限定符

不想给别人用的设置成 私有的

private:
	int* a;
	int top;
	int capacity;
};

三、类的两种定义 1,声明和定义全部放在类中

成员函数如果在类中定义,函数符合inline条件(编译指令比较少)会将其当成内联函数处理

2,声明和定义分离

假设要实现一个队列,就是头文件里面放结构的定义和成员函数的声明

//.h

class QueueNode
{
public:
	int val;
	QueueNode* next;
};

class Queue
{
public:
	void Init();
	void Push(int x);
	void Pop();
private:
	QueueNode* head;
	QueueNode* tail;
};

函数的定义放到源文件里面

//.cpp

void Queue::Init()
{
	//...
}

void Queue::Push()
{
	//...
}

void Queue::Pop()
{
	//...
}

因为类自己也是一个域,所以在类体外定义成员需要用 :: 作用域解析符指明成员属于哪个类域,所以前面要加一个 Queue:: 如果不加的话它默认是个普通函数,只会在局部找,再去全局找,再去展开的命名空间找,都找不到(C++中只要是 { } 括起来的都叫域,域要么影响生命周期,要么影响访问)

声明和定义分离的意义在于方便阅读代码,比如一个类里面光成员函数就有一百个,这个时候把声明和定义放在一起去看这个代码的时候就很不方便。


类的定义:

1,小函数想成为inline直接在类里面定义即可

2,如果是大函数,声明和定义应该分离


封装

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现的细节,仅对外公开接口来和对象进行交互。封装本质上是种管理,让用户更方便使用。

比如:对于电脑这样一个复杂的设备,提供给用户的只有开关机、键盘输入、显示器、USB插孔等,让用户和计算机交互,但实际上电脑真正工作的是它的那些硬件元件。对于使用者而言,不必去关心内部核心部件,线路布局,CPU的设计等。

四、类的实例化

在这个类里面的成员都是声明,函数的声明和定义很容易区分,那变量的声明和定义怎么区分就要看它有没有开空间,开空间的就是定义,不开空间的就是声明。

int a;                        //定义

class Book
{
public:
	void PrintInformation();  //声明
public:
	char name[20];            //声明
	int price;
	int number;
};

只有用这个类去定义一个对象的时候它才会开空间,这个过程就叫类的实例化。

类它是不占空间的,它要去实例化出对象,这个对象才占空间。

int main()
{
	Book b;

	return;
}

那又有一个问题,它在没有开空间的情况下,用 sizeof 去算这个大小,它是去怎么算它的大小的呢?

做个比方,形象一点说就是用图纸去建造房子一样,类呢就是一个设计图,这个设计图不能住人,但是可以根据这个图纸来算这个房子有几个房间,每个房间能住几个人,一合计,也能算出来,不一定要实例化后才能算。

int main()
{
	cout << sizeof(Book) << endl;  //28

	return 0;
}
五、类对象模型

我们如何来算这个类的大小呢?

class A
{
public:
	void Print()
	{
		cout << a << endl;
	}
private:
	char a;
};

从结果来看,说明 Print  不算成员函数

int main()
{
	cout << sizeof(A) << endl;  //1

	return 0;
}

那为什么它在这里不算成员函数呢?这就和它的存储方式有关,它用的就是下边第三种方式。

类对象的存储方式

一种呢就是它全部储存到一起,但这样的设计缺陷在于浪费空间,如果实例化的对象比较多,每个对象都是独立的空间都要存一个成员函数,而这些成员函数都是一样的,相同的代码就会保存多次。


所以有人就提出了另一种方案,把代码专门提取到一个单独的地方,形成一张表,类似指针数组,这样一来就只需要存一份,不需要存多份,就没有那么多浪费,那么我们要找函数就去这张表里找就可以了。


第三种方案,对象里面只存成员变量,成员函数不占对象的空间,也不用一个指针去指向它,它把成员函数直接存在一个公共的代码段,跟普通的函数一样,这时,对象和成员函数没有关联了,那它又是怎么去找的呢?因为它在编译链接时就根据函数名去公共代码区找到了函数的地址。

 那么下面这段代码,是崩溃,还是编译出错,还是正常运行呢?

class A
{
public:
	void func()
	{
		cout << "A" << endl;
	}
private:
	char a;
};

int main()
{
	A* ptr = nullptr;
	ptr->func();

	return 0;
}

结果是正常运行,如果他采用的是第一种或者第二种,那么它都会崩,第一种是去对象里找这个函数的地址然后调用,第二种是去对象找到函数表的地址去找到这个函数,也会崩,因为 ptr 指向的是一个空指针,而第三种正常运行的原因就是 ptr 不会去对象里面找,所以不会去解引用这个空指针, func 没有存在对象里面,在代码区里,编译的时候就已经找到它的地址了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1029360.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号