在这篇博客中,前言是最后写的!因为不知道该如何去总的介绍这篇博客,其实说白了就是没有一个很好的顺序去阅读!关于第一部分内容其实可以先略过,八股文似的内容总归是没人喜欢的!但是思来想去这种东西又不得不放在最前面,而这部分内容可以先跳过去,等看完下面的内容重现去看第一个,此时或许会变得没那么枯燥繁琐!当然,类和对象的特点这里也只是做了一个概述,关于其封装性等等特征都是没有介绍的;本篇内容也是依托于谭浩强老爷子书中进行的,所以需要了解其他更多内容的话,还是比较推荐谭浩强的C++ 这本书的!
C++是由C的基础上演变而来的,而C++最大的改变就是由面向过程转变为面向对象。于C语言来看,函数是构成程序的基本部分,程序面对的是一个个函数,每个函数都是独立存在于程序中,但是又可以互相调用;而在C++而言除了主函数,其他的函数都是出现在类中的,只有通过类才能调用类中的函数,此时程序的基础部分变成了类,程序面对的是类和其对象,此时程序的设计过程即是面向类的,也就是面向对象的!
上面所述的类和对象究竟是什么呢?其实看完下面再去读上面的内容就会有不一样的理解了!
在客观世界中任何一个事物都可以看做一个对象;举个例子,学生在一个班级中上课、开会、体育比赛等。
看黄色标记的这句话,学生的专业、人数、教室都是静态特征,这种静态特征叫做属性,而上课、开会、体育比赛都属于动态特征,这种动态特征被叫做行为!而上述的这个班级就叫作对象。
至此,任何一个对象都应该具有两个要素:属性和行为!
例如,张三、王五、李四我们将其归纳为中国人一类;而中国人、美国人、等我们将其归纳为人一类;1,2,3被归纳为正数一类。而这一些过程有一个名称叫做“抽象”;
换言之,抽象就是表示同一类事物的本质,将具有共性的一部分对象归纳为一个整体;而这种抽象形成的一种类型在C++中则被叫做类;
所以说,类是对象的抽象,对象则是类的实例化,也就是类的具体表现形式
在C++中对象的类型叫做类,类代表了某一批对象的共性和特征!在C++中声明了一个类,用它去定义若干个同类型的对象。对象就是类类型的一个变量!
类是抽象出来的一种共有的特征,是不占用内存的,而对象则是一个具体的,是占用内存空间的。
在C语言中,结构体可以包含不同类型的变量:
struct Student
{
int num;
char sex;
char name[20];
};
上面的结构体是不包含具体的行为(操作),只有数据(变量)。
而在C++中,则引入了这样的方法:
class Student
{
int num;
char sex;
char name[20];
void Display()
{
cout << num << endl;
cout << name << endl;
cout << sex << endl;
}
};
可以看到,声明类的办法是由C语言的结构体演变而来的;类有关键字class和类名student;其中除过数据之外,还有一个函数display。
其实在C++中,struct结构体里面也是可以定义函数的了,这一点可以上机验证一下,只不过在C++中更喜欢将其叫做class!
class Student
{
int num;
char sex;
char name[20];
void Display()
{
cout << num << endl;
cout << name << endl;
cout << sex << endl;
}
};
我们希望:在类中只有类中的函数去调用改变内部的数据变量,在类外去调用操作数据的相关函数;因此,不能将类中的成员全部与外界隔离开来,一般情况是将数据隐藏起来,而将成员函数作为对外界的接口。所以我们就需要对其成员变量以及成员函数进行范围访问的约束!
private:私有的成员变量和成员函数
public:共有的成员变量和成员函数
protected:受保护的成员(后续内容进行论述)
所以,对上面的类进行修改就是:
class Student
{
private:
int num;
char sex;
char name[20];
public:
void Display()
{
cout << num << endl;
cout << name << endl;
cout << sex << endl;
}
};
而需要注意的是,C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类,它和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private。
在前面说过,类是抽象的,是不占用内存空间的;其实你会发现类似class、struct这种都是我们自定义的类型;既然是类型,那么不占空间也就合理了;只有用这种类型去定义对象(变量)时,才会产生内存;
在谭老爷子的书中,给出这样一个例子:好比建造房屋需要先设计图纸,然后按图纸在不同的地方建造若干栋同类的房屋;在这里图纸就是我们的类,将图纸显示于现实中,此时就完成了类的实例化。
总之:类是对象的抽象,对象是类的实例化!
1️⃣声明类的同时定义对象
class Student
{
private:
int num;
char sex;
char name[20];
public:
void Display()
{
cout << num << endl;
cout << name << endl;
cout << sex << endl;
}
}std1, std2;
在定义Student的同时定义两个Student类的对象。
2️⃣先声明类型在定义对象
class Student
{
private:
int num;
char sex;
char name[20];
public:
void Display()
{
cout << num << endl;
cout << name << endl;
cout << sex << endl;
}
};
int main()
{
class Student std1;//class 类名 对象名
Student std2;//类名 对象名
return 0;
}
3️⃣不出现类名,直接定义对象
class
{
private:
int data1;
int data2;
int data3;
public:
void Display()
{
//...
}
}ob1, ob2;
此种定义不出现类名,直接定义对象;而在一般情况下这种方法几乎不用,因为在类的声明和类的使用是分开的,类并不只是为一个程序服务的;这种定义的方法与struct结构体的其中一种定义一样都是不经常使用的!
我们从前面可以知道,对于类而言其实是可以分为两部分的,一部分是数据,一部分是操作;数据大多时候都是私有的,不被外界所看见发现的,操作大多数是被定义成public的,可以被外界正常调用。
程序中,访问对象中的成员是存在三中和方法的!
class Data
{
private:
int num1;
int num2;
public:
void Init(int a, int b)
{
num1 = a;
num2 = b;
}
void Display()
{
cout << num1 << " " << num2 << endl;
}
};
1️⃣通过对象和成员运算符访问对象中的成员
Data da;
da.Init(3, 4);
da.Display();
//当然如果内部数据是共有的话,我们此时也可以引用内部数据
2️⃣通过指向对象的指针访问对象的成员
Data* pd = &da;
pd->Display();
3️⃣通过对象的引用来访问对象中的成员
Data& ff = da;
ff.Display();
我们知道,同一类的多个对象中的数据成员的值一般是不相同的,而不同的对象的函数代码是相同的,因此我们在相同类型不同对象调用相关的函数时,其实本质上调用的代码是一样的!
我们看如下代码经过调试反汇编后所调用的函数其实是一样的!
int main()
{
Data d1;
d1.Init(3, 4);
Data d2;
d1.Init(5, 6);
}
其实,在研究类时我们应该与C语言的结构体结合起来一起来看;而下述代码的输出是什么呢?
class Data
{
private:
int num1;
int num2;
public:
void Init(int a, int b)
{
num1 = a;
num2 = b;
}
void Display()
{
cout << num1 << " " << num2 << endl;
}
};
int main()
{
Data d1;
cout << sizeof(d1) << endl;
}
既然调用成员函数时所调用的代码是一样的,因此每个对象所占的存储空间只是该对象的数据成员所占用的存储空间,而函数代码则是存放在一个公共的区域了!因此上述代码的结果是8!
此时存在一个问题,就是如果成员函数并不放在对象的存储空间中的话,那么对象的成员函数这个说法是否成立呢?
其实,我们所说的“某某对象的成员函数”是从逻辑上出发的,而成员函数的存储方式则是从物理的角度出发的,是由计算机优化的,这二者并不冲突。物理上的实现保证了逻辑上的实现!
在经过上述内容后,是否大家有过这样的一个疑惑?就是为什么不同对象执行的都是一段相同的函数代码,但是执行结果却是不同的!
这是因为C++设置一个名为this指针的东西用来指示不同的对象,当调用对象d1的成员函数时,this指针就指向了d1;在函数体中所有的“成员变量”都是通过指针去访问的,只不过不需要用户去传递,编译器自动就会完成这件事情!
this指针的特性:
1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
2.只能在“成员函数”的内部使用。
class Data
{
private:
int num1;
int num2;
public:
void Init(int a, int b)
{
num1 = a;
num2 = b;
}
void Display()
{
cout << this->num1 << " " << this->num2 << endl;
}
};
3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递
上述就是this指针的特性,需要注意的是规定this指针是被* const修饰的,所以不能更改!而this指针其实是成员函数的第一个隐藏形参,这个形参是由编译器自己传递参数完成一系列操作的,我们不需要管;既然this指针是成员函数的形参,函数的形参是存储在栈帧里面的,因此this指针也即是存在栈区内的!
class Data
{
private:
int num1;
int num2;
public:
void Init(int a, int b)
{
num1 = a;
num2 = b;
}
void Display()
{
cout << this << endl;
cout << this->num1 << " " << this->num2 << endl;
}
};
int main()
{
Data da;
da.Init(3, 4);
da.Display();
cout << &da << endl;
}
这个代码就很形象的展示了this指针其实就是指向了实例化的对象,this这个形参的内容就是对象的地址,只不过这个参数的传递等是由编译器完成的!
类和对象的基础入门已经结束了,其实这部分内容算不上难,只是需要注意的点是比较多的;如我,在刚接触类和对象时,根本搞不清什么是对象,什么是方法等;各种书上对此类概念解释的比较枯燥!所以仍然需要重复研读几遍!