本篇主要讲述以下内容:
1.类与对象的初步认知
2.类的引入 和定义
3.类的访问限定符及封装
4.类的实例化
5.类对象模型
6.this指针
1.类和对象的初步认知:
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
简单来说类就是现实中一些具有共同特性事物的抽象,它包括这个事物的一些属性和你想对这个事物的操作,而对象就是对一个类的实例化。比如你现在想要买10台电脑,这10台电脑的总和就是一个类他们就有共同的特征,现在你想给其中一台装一个软件,这一个就是这个类实例化出来的对象,你对这个对象的操作并不影响其他9 个产生影响。
2.类的引入和定义
在c语言中我们常常用结构体来描述一个事物比如我要定义一个学生类,在c++中我们同样也可以使用结构体,不同的是结构体内不仅可以定义变量,还可以定义函数。
struct student
{
oid SetStudentInfo(const char* name, const char* gender, int age)
{
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
void PrintStudentInfo()
{
cout << _name << " " << _gender << " " << _age << endl;
}
char _name[20];
int _age;
char name[3];
};
但在c++中我们通常将其定义为类,class为定义类的关键字,student为类的名字,{}中为类的主体,注意类定义结束时后面分号。
类中的元素称为类的成员:类中的数据称为类的属性或者成员变量; 类中的函数称为类的方法或者成员函数。
类的定义和声明可以放在一起,也可以声明放在.h文件中,类的定义放在.cpp文中
//.h文件
class student
{
public:
void cinstudent();
private:
char _name[20];
int _age;
char _gender[3];
};
//.cpp文件
#include"student.h"
void student::cinstudent()
{
cout << _name << _age << _gender << endl;
}
/
将定义和声明放在一起
class student
{
public:
void student::cinstudent()
{
cout << _name << _age << _gender << endl;
}
private:
char _name[20];
int _age;
char _gender[3];
};
那么C++中struct和class的区别是什么?
因为C++需要兼容C语言,所以C++中struct可以当成结构体去使用。另外C++中struct还可以用来定义类。 和class是定义类是一样的,区别是struct的成员默认访问方式是public,class是struct的成员默认访问方式 是private。
3.类的访问限定符及封装
c++的一个特性封装特性,那么c++是如何实现封装特性的呢?
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的实现了类的封装特性)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- class的默认访问权限为private,struct为public(因为struct要兼容C)
那么类的封装到底是什么呢?
封装的概念:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行 交互。
封装本质上是一种管理:
比如我们如何管理兵马俑呢?比如如果什么都不管,兵马俑就被随意破坏了。那么我们 首先建了一座房子把兵马俑给封装起来。但是我们目的全封装起来,不让别人看。所以我们开放了售票通 道,可以买票突破封装在合理的监管机制下进去参观。类也是一样,我们使用类数据和方法都封装到一下。 不想给别人看到的,我们使用protected/private把成员封装起来。开放一些共有的成员函数对成员合理的访 问。所以封装本质是一种管理。
4.类的实例化和作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用 :: 作用域解析符 指明成员属于哪个类域。
void student::cinstudent()//此处需要说明cinstudent是属于student这个类域
{
cout << _name << _age << _gender << endl;
}
用类类型创建对象的过程,称为类的实例化
- 类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
- 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什 么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占 用物理空间
class student
{
public:
void student::cinstudent()
{
cout << _name << _age << _gender << endl;
}
public:
char* _name;
int _age;
char* _gender;
};
void Test()
{
student man;//man就是student类实例化出的对象
man._name="xaio";
man._age = 18;
man._gender = "男";
}
5.类对象模型
1.计算类对象的大小
先看代码:
class A1
{
public:
void f1(){}
private:
int _a;
};
// 类中仅有成员函数
class A2
{
public:
void f2() {}
};
// 类中什么都没有---空类
class A3 {};
int main()
{
cout << sizeof(A1) << endl;
cout << sizeof(A2) << endl;
cout << sizeof(A3) << endl;
system("pause");
return 0;
}
//通过运行代码可知:sizeof(A1) : _4__ sizeof(A2) : __1____ sizeof(A3) : ___1___
因此一个类的大小,实际就是该类中”成员变量”之和,当然也要进行内存对齐,注意空类的大小,空类比 较特殊,编译器给了空类一个字节来唯一标识这个类
6.this指针
定义一个日期类
class Date
{
public:
void Display()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
void
SetDate(int year, int month, int day)
{ _year = year;
_month = month;
_day = day; }
private:
int _year; // 年
int _month ; // 月
int _day ; // 日
};
int main()
{ Date d1, d2;
d1.SetDate(2018, 5, 1);
d2.SetDate(2018, 7, 1);
d1.Display();
d2.Display();
return 0;
}
这个类中有两个成员函数,当s1调用SetDate函数是他怎么知道是设置s1还是s2?
C++中通过引入this指针解决该问题,即:C++编译器给每个“成员函数“增加了一个隐藏的指针参数,让该指 针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访 问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
this指针的特性
(1)名称属性:标识符this表示。
(2)类型属性:类类型* const(类似于类引用的类型)
(3)值属性:表示当前调用该函数对象的首地址。
(4)作用域:this指针是编译器默认传给类中非静态函数的隐含形参,所以其作用域在非静态成员函数的函数体内。
(5)链接属性:在该类作用域中,不同类的非静态成员函数中,this这个指针变量的链接属性是内部的,但其所指对象是外部的,即this变量是不同的实体,但指向对象是同一个。
(6)存储类型:this指针是由编译器生成,当类的非静态成员函数的参数个数一定时,this指针存储在ecx寄存器中;若该函数参数个数未定(可变参数函数),则存放在栈中。
(1):this指针是什么时候创建的?
this在成员函数的开始执行前构造的,在成员的执行结束后清除。
(2)this指针可以为空吗?
因为this指向一个已存在的类的实例对象,可以通过"->"的方式,访问类中成员,左移this为空是非法的。
this的用法
我们可以通过this访问一个对象的具体成员
void printfmonth()//定义一个打印month的函数在日期类中
{
cout << this->_month << endl;
}
Date func()//定义一个返回对象的函数
{
return *this;
}
d1.printfmonth();//调用打印月份的函数
d2.printfmonth();
d1.func();//调用func函数