目录
前言:
面向过程和面向对象的区别:
C语言:
C++:
类的引入:
类的定义:
类的权限:
类的作用域:
类的实例化:
类的大小计算:
空类或则只有成员函数的类:
this指针:
前言:
通过学习我们总是能够听见有人说C语言是面向过程编程,而C++是面向对象编程。但是对于我们接触C++不久的同学或则是对C语言的理解不够深刻的同学来说,对于这两个区别并不大,包括我来说也是如此,因为我们本身对于代码量的积累,项目的实践太少了,不过通过下面的讲解,估计可以让你在脑海中形成一种思维来区别它们。
面向过程和面向对象的区别:
我们分别利用C和C++的方式对洗衣服这一件事情进行描述。
C语言:
上图描述了我们用C语言完成洗衣服这一过程的描述,对于C语言来说,每一步要做什么都是需要我们自己考虑清楚,并且它们之间的顺序不能改变,否则整个过程就会出现问题,导致程序BUG,当然不能考虑删除部分代码程序莫名能跑的奇怪情况。
C++:
对于C++来说,我们实现洗衣服这一个过程一共需要4个对象:人,衣服,洗衣粉,洗衣机,然后这4个对象之间相互交互,最终实现问题,对于对象谁先出现谁后出现,它们是如何完成的这一过程我们不需要知道。
上述讲解有些抽象,我这里用人话将就是说,C++将一个对象描述起来了,就像是C语言的结构体一样,描述一个学生,需要它的名字,学号等等信息,不过C++比起C语言来说多了一个新的功能,那就是允许在这个结构当中添加成员函数,这就是面向对象最关键的部分,这意味着这一个对象实现之后,我们只需要通过它提供的函数接口就能知道这个对象能够实现哪一些功能,然后通过我们自己的发挥与其它对象提供的函数接口进行交互,从而达到最终的目的。
类的引入:
C语言的结构体当中只能定义变量,但是你创建一个cpp文件之后,你会惊奇的发现,结构体当中还能够定义函数了。
struct test
{
void test1()
{
cout << "hello world" << endl;
}
int a;
int b;
};
类的定义:
class test
{
};
虽然在C++中可以用结构体来写类,但是对于C++来说,我们更习惯于用class来代替,结构体和类对于当前的我们来说是没有区别的,但是是有一点需要注意,那就是它们的默认访问权限不同,结构体中是公有权限,而类中是私有权限。
类的权限:
类的权限有三种,public(公有)、protected(保护)、private(私有),通过在类里面写下这几个关键字,可以更改成员权限,权限的作用域从关键字到下一个关键字或则结束。
公有权限表示类内部能够访问,类外部也能够访问、子类也能够访问。
保护权限表示类内部能够访问,类外部不能够访问、子类能够访问。
私有权限表示类内部能够访问、类外部不能访问、子类不能访问。
不过现在我们还没有学习关于继承相关的知识,所以说保护权限和私有权限对于我们来说是一样的。
class Stu
{
//公有权限:(外部能够访问,内部能够访问)
public:
//声明(在类外部可以定义)
void set(int num, int score);
void change(int num, int score);
//直接在函数内部
void print()
{
cout << _num << endl;
cout << _score << endl;
}
void print2()
{
cout << "hello world" << endl;
}
int a;
//保护权限:(外部不能访问,子类可以访问,内部可以访问)
protected:
//私有权限:(只有内部可以访问,其它都不能访问)
private:
//在类里的变量名添加一个下划线是为了避免与函数的参数相同
//因为变量查找是从最近作用域到外逐渐查找的,避免之后函数
//内部访问不到我们的类信息
int _num;
int _score;
};
类的作用域:
类的实现实际就是实现了一个新的作用域,它里面所有的成员都在类的作用域当中,当类外定义内部成员时需要用::作用域操作符指明作用域。
class Person
{
public:
void PrintPersonInfo();
private:
char _name[20];
char _gender[3];
int _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
cout << _name << " "<< _gender << " " << _age << endl;
}
类的实例化:
用类创建一个对象的过程就被称为类的实例化,判断一个变量是声明还是实例化只需要通过判断编辑器是否实际分配了内存空间。
//类的声明
class test
{
public:
void print()
{
cout << "hello world" << endl;
}
};
void test2();
int main()
{
//类的实例化
test t1;
}
可以理解为我们将一个类描述了出来,但是没有实际分配空间给他,就被称为声明,我们通过这个类去定义一个变量,编辑器就会为这个变量分配空间。
类的大小计算:
类的大小计算和结构体是一模一样对齐方式,在32位机器下,下一个变量的字节加上前面的字节数超过了8个字节就会另外开辟一个新的8个字节存储该变量,vs下是8个字节,根据实际的编辑器来考虑,计算完成之后的对齐数必须是最大变量类型的整数倍或则是默认对其数的整数倍,谁小就是谁。嵌套了结构体,嵌套的结构体对齐到字节的最大对齐数的整数倍。
空类或则只有成员函数的类:
当一个类里面什么都没有时,它的大小也不会是0,因为通过我们对实例化的理解,如果不分配一个空间给他那就不算时实例化,如果字节为0,到底算不算是实例化呢,所以编辑器会主动为我们的空类分配1字节的空间,作为一个占位符,没有其它意义,有变量的时候编辑器不会给。
当类里面只有成员函数,它的大小还是1,有朋友会想,函数的地址在32位编辑器下不是4个字节吗,为什么会不占用内存?事实上,并不是函数不占用内存,而是函数的空间被放到了一个名为代码段的存放区域。
原因也是很容易想到的,如果我们实例化一个空间就对这个函数分配一个空间,那么势必会导致空间的浪费,因为这些函数实现了一模一样的功能,它们又不分辨里面的数据,所以才会将其移动出去。
struct test
{
void test1()
{
cout << "hello world" << endl;
}
};
class Stu
{
public:
void print()
{
cout << _num << endl;
cout << _score << endl;
}
private:
int _num;
int _score;
int a;
};
this指针:
想必大家在学习类的时候一定是听过一个东西this,他作用于对象里面,大家也没有写它,但是就是在非静态函数当中能够使用它,那么这是为什么呢?
void Stu::change(int num, int score)
{
//函数是如何分辨_num和_score的所属?
_num = num;
_score = score;
}
Stu s1;
//表面上我们的传参
s1.change(1, 2);
//实际上编辑器的传参
s1.change(&s1, 1, 2);
通过上述代码,我们看到了change函数只有两个参数,我们传参也是传了2个,但是编辑器为我们悄悄做了一件事情,那就是将我们的传参中添加一个&s1,得到了s1的地址,这样我们就能够使用s1里面的成员了。
但是如果传入三个参数又与我们的函数对应不上,所以编辑器为我们将函数改了。
void Stu::change(Stu* this, int num, int score)
{
//正常写法当中写上this和不写是一样的,我们不写编辑器会为我们写
this->_num = num;
this->_score = score;
}
这一过程我们自己是不能写的,写了就错,我只需要知道编辑器为我们做了这一件事情就行。
既然编辑器会传地址过去,那我们传一个空指针能行吗?
答案是能行,并且我们还能够调用部分函数。能调用函数的原因大伙看了上面类的大小应该是能够理解的,因为类里面的函数是存储在代码段当中的,所以调用它的函数不算是空指针解引用,但如果我们使用了他里面的成员变量,这就不对了,因为成员变量在类里面分配了空间,使用它就是对空指针解引用,导致错误。
以上就是咱们初次认识类的内容啦。