类和对象(上)

本文介绍了C++中的面向对象编程概念,包括类的定义、类的访问控制(公有、保护、私有)、类的封装、this指针的作用及其特点。通过外卖行业和C/C++实例,对比了面向过程与面向对象的差异,并详细解释了类对象的存储方式以及this指针在成员函数中的运用。
摘要由CSDN通过智能技术生成

目录

1.面向过程与面向对象

2.类的定义

3.类的访问限定符及封装

1>.访问限定符

2>类的作用域

3>.c++的一些约定

4>.封装

5>.类的大小

 

6>.类对象的存储方式

 

4.this指针

1.this指针特点 

2.this指针的面试题


1.面向过程与面向对象

C语言是面向过程的语言,关注的是解决问题的过程与方法。  C++可以说是C语言的延伸与发展,不仅继承了C的一些优势,而且还多了一样非常重要的东西——面向对象。

那面向过程和面向对象有什么区别呢? 

我们知道,外卖产业需要四方的支持才能产生:顾客、商家、骑手、平台。

面向过程就类似研究如何实现这一过程的每个步骤的运转成立。 先让顾客下单,平台处理向骑手发布任务,骑手接单到商家取餐,最后送至顾客。它考虑的是每一个过程的如何实现。

面向对象是分模块来完成,顾客、平台、商家、骑手四个模块,分别干什么,让他们各自处理各自的事情,是以对象为基准来实现运转。

如果从程序的实现角度来说,C语言这种面向过程的就必须要将每一方的行动做成函数,逐一实现

面向过程则可以将每一方封装起来,不管是他的信息还是行为,都可以全部装到一起,没必要一个动作一个动作写成函数再调用,可以全部放到一个类下面。

意思就是,C++的结构下,可以将信息(如:人的年龄、性别等变量)和动作(函数)放到一个类下,这是C语言做不到的。

举个例子。

(c语言实现)

struct stu
{
	char name[20];
	int age;
	char ID[19];
	//...
};
struct teacher
{
	int name;
	int age;
	char ID[19];
	//...
};
 
void StuReturnSchool(struct stu* ps)
{
	//...
}
 
void TeaReturnSchool(struct teacher* pt)
{
	//...
}
 
void StuRegisterSchool(struct stu* ps)
{
	//...
}
 
void TeaRegisterSchool(struct teacher* pt)
{
	//...
}

c++实现 

class stu
{
	char name[20];
	int age;
	char ID[19];
	//...
	void StuReturnSchool(stu* ps)
	{
 
	}
	void StuRegisterSchool(stu* ps)
	{
 
	}
};
 
class teacher
{
	int name;
	int age;
	char ID[19];
	//...
	void TeaReturnSchool(teacher* pt)
	{
 
	}
	void TeaRegisterSchool(teacher* pt)
	{
 
	}
};

因此,面向对象的优势此时就被体现出来了。

我们可以将老师作为一个整体封装到一个类下面。里面不仅存老师的信息,也存老师的登录、报到等一系列动作的函数接口。这样就方便很多了,而且看上去也是一目了然。

2.类的定义

C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。
class className
{
// 类体:由成员函数和成员变量组成
};  // 一定要注意后面的分号
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面
号不能省略
类体中内容称为类的成员:类中的变量称为类的属性成员变量; 类中的函数称为类的方法或者
成员函数
C++变量和函数都在一个类里面,有必然的联系,因此可以上函数下变量的方式书写。
类的两种定义方式:
1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成
联函数处理。

2.类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::

在实际应用中尽量用第二种 

3.类的访问限定符及封装

1>.访问限定符

C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。 而上面的就是我们访问权限。
public(公有):公有修饰的成员在类外可以直接被访问
protected(保护):类外不可以访问,自己的成员函数内可以访问。
private(私有):和保护相似,具体区别会在后面展开。
注意:访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。

在C++中struct和class的区别: class的默认访问权限为private,而struct的默认访问权限为public(因为在C++中struct要兼容C)

2>类的作用域

类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 ::
作用域操作符指明成员属于哪个类域。
class STU
{
public:
	void Show();//成员函数
private:
	//成员变量
	char _name[10];//学生姓名
	int _math;//学生数学成绩
	int _chinese;//学生语文成绩
};
//这里需要指定Show函数是属于STU这个类域
void STU::Show()//成员函数
{
	cout << "姓名:" << _name << "  数学:" << _math << "  语文:" << _chinese << endl;
}

3>.c++的一些约定

我们在类里定义变量时,通常会在前面或后面加_  以示区分。
int_year;
int_day;

4>.封装

面向对象有三大特性:封装、继承、多态。这三个是最主要的。

我们现在所学的类就是封装的一大体现。其本质就是把一系列相关的东西都封到一个地方。

类里面有公有和私有,想给外面使用的就设为公有(如成员函数,不想给外面使用的就设为私有(如成员变量)。

以数据结构的栈为例,C语言实现的时候相对自由一些,它的数据和方法(变量和函数)不是在一起的,是分离的。 而C++则是将数据和方法都封装在了一个类下。


5>.类的大小

只计算成员变量的大小

我们看到成员变量中 含有静态变量后的结果依然是8

空类


 

结论:一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐

注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。

不论是类里面只有函数没有变量,还是什么都没有,编译器默认给的大小是1,不是0

也就是说编译器会给1个字节占位,它不存储有效数据,仅标识类存在

  结构体内存对齐规则(可以去c语言专题去看)
1. 第一个成员在与结构体偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的对齐数为8
3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

 

 

6>.类对象的存储方式

为什么成员变量在对象中,成员函数不在对象中呢?

每个对象成员变量时不一样的,需要独立存储

每个对象调用成员函数是一样的.放到共享公共区域(代码段)..

 

4.this指针

class Date
{
public:
	void Init(int year = 1,int month = 1,int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << " " << _month << " " << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2;
	d1.Init(2022,1,1);
	d2.Init(2022,1,2);
	d1.Print();
	d2.Print();
	return 0;
}
Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函
数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?
C++中通过引入this指针解决该问题,即: C++编译器给每个“非静态的成员函数“增加了一个隐藏
的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”
的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编
译器自动完成。

1.this指针特点 

1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
(如:this = nullptr(X))
2. 只能在“成员函数”的内部使用
3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给
this形参。所以对象中不存储this指针。
4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传
递,不需要用户传递

2.this指针的面试题

1.. this指针存在哪里?

栈里面,因为他是隐含形参

2.看下面两个代码的区别

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
 void Print()
 {
 cout << "Print()" << endl;
 }
private:
 int _a;
};
int main()
{
 A* p = nullptr;
 p->Print();
 return 0;
}

这个答案是C,正常运行,为什么呢

上面已经说了,成员变量在对象中,成员函数在公共代码段

这里先看函数在不在对象里面,不在的话要去公共代码段里面

p是空指针不假,但是注意:print函数的地址是在公共代码区的(代码段),而非在对象里,编译器去找print函数不会去对象里找,而是直接去代码段,所以这里p->Print()不发生解引用。p是A的指针,直接传给print函数的this指针,指针可以为空,不会报错,因此正常运行,第一题选C。

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{ 
public:
    void PrintA() 
   {
        cout<<_a<<endl;
   }
private:
 int _a;
};
int main()
{
    A* p = nullptr;
    p->PrintA();
    return 0;
}

这个B运行崩溃

为什么呢?

_a是成员变量,在对象里面去找,this指针会解引用,空指针解引用会报错

cout << this->_a << endl;

->不一定是解引用,解引用是看他是否在对象里面去找

文章参考了一些大佬的资料,谢谢观看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值