[baka编程]初入C++,如何理解新概念——类和对象
1.类的定义
1.1类定义的格式
举个例子,
class baka
{
public:
int CirnoMathClass()
{
return 9;
}
private:
int _cirno;
int _ice;
};
class为定义类的关键字,baka为类的名字,{}中为类的主体,注意类定义结束时,后面的分号不能省略。
类中的内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或成员函数。
为了区别成员变量,一般习惯上成员变量上会加一个特殊标识,如成员变量的前面加上一个_或者一个字母m(任意字母),并不强制,只是作为一种惯例。
定义在类中的成员函数默认为inline函数(上篇可见)
而在C++中struct也可以定义类,C++兼容C中struct的用法,同时struct升级为了类,明显的变化是struct中可以定义函数,不过一般情况下还是推荐用class来定义类。
1.2访问限定符
三个访问限定符如下,
访问限定符是C++一种实现封装的方式,用类将对象的属性与方法结合在一起,让对象更加完善,通过访问限定符权限选择性的将接口提供给外部的用户进行使用。
public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能直接被访问,protected和private是⼀样的,以后继承章节才能体现出他们的区别。
访问权限作用域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为止,如果后面没有访问限定符,作用域就到}即类结束。
class定义成员没有被访问限定符修饰时默认为private,struct默认为public。
⼀般成员变量都会被限制为private/protected,需要给别⼈使用的成员函数会放为public。
1.3类域
类定义了一个新的作用域,类的所有成员都在作用域中,在类外定义成员函数时,需要使用::作用域操作符指明成员属于哪个类域。
类域影响的是编译的查找规则,下面函数中如果不指定类域,那么编译器就会把函数当成全局函数,那么编译时,就会因为找不到cirno成员的声明,那么就会报错。如果指定了类域,在全局函数中找不到定义就会到类域中去查找。
class baka
{
public://成员函数
int CirnoMathClass();
private:
int cirno;
int ice;
};int baka::CirnoMathClass()
{
cout << cirno << endl;
}
2.实例化
2.1实例化概念
用类类型在物理内存中创建出对象的过程成为类实例化出对象。
class baka
{
private:
int _cirno;
};
int main()
{
//ice就是实例化出的对象
baka ice;
}
类是对象的一种抽象描述,是类似房子图纸一样的东西,限定了类有哪些成员变量,但是不能储存变量,它没有实体,因为这些变量只是声明,并没有配给空间,只有类实例化出对象时,也就是将房子按照图纸建出来时,才会分配空间。而且可以依照图纸建出多个房子,也就是说类可以实例化出多个对象。
2.2对象的大小
在C语言中baka都知道结构体变量按照内存对齐规则来储存,那么C++呢?在C++中,类是可以有成员函数的,那么成员函数会储存在类中吗?
答案是,成员函数不会储存在类中。举个简单的例子,baka有九个对象,类中有一个成员函数,那么baka在使用这些对象时,调用的成员函数是同一个函数还是九个函数呢?从效率方面考虑,调用的是同一个函数,因为创建九个函数栈帧看起来不是很繁琐吗!而且这还会增加对象的大小,不浪费储存空间吗!所以C++中的成员函数不储存在对象中。
既然这样,类中只有成员变量的存在,那不就和结构体差不多嘛!所以类的对象也遵守内存对齐规则:
1.第一个成员在与类偏移量为0的地址处
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
3.对齐数=min(编译器默认的对齐数,该成员的大小)(取较小值)
4.类的总大小为最大对齐数(所有类型变量的最大值和默认对齐数取小)的整数倍
5.如果嵌套了类,那么嵌套的类对齐到自己最大对齐数的整数倍,那么类的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
如果类中没有成员变量,为了展现类存在过,类的对象大小为1字节。
3.this指针
先来看下面一段代码
#include<iostream>
using namespace std;class baka
{
public:void Init(int cirno = 9, int ice = 3);void CirnoMathClass();
private:int _cirno;int _ice;
};void baka::CirnoMathClass()
{cout << _cirno << " baka " << _ice << " icecream " << endl;
}void baka::Init(int cirno, int ice)
{_cirno = cirno;_ice = ice;
}int main()
{baka b1;baka b2;b1.Init(3, 9);b1.CirnoMathClass();b2.Init();b2.CirnoMathClass();return 0;
}
运行时可以看到控制台的输出为,符合baka的预期
那么问题来了,b1和b2都调用了Init和CirnoMathClass,那这些函数怎么知道是谁调用的他们呢,函数体内好像没有对对象有区分口牙?其实是C++给了一个隐藏的this指针,它指向的是调用函数的对象。
当编译器编译后,类的成员函数默认会在形参的第一个位置,增加一个当前类类型的指针叫做this指针,比如。
void Init(baka* const this,int cirno = 9, int ice = 3);
void CirnoMathClass(baka* const this);
类成员函数访问成员变量,本质都是通过this指针访问,如Init中的赋值实际上为
this->_cirno=cirno;
this->_ice=ice;
而C++规定不能在实参和形参的位置显示的写this指(因为编译器会处理),但是可以在函数体内显示使用this指针。
值得注意的是,this指针不存在类中,而是存在栈中,不然前面的理论就被推翻辣!