类与对象(上),咕咕咕
1.类的定义
class 是定义类的关键字,之后跟类的名字,{}中为类的主体,类定义结束后的分号不能省略。类体中的内容称为类的属性或成员变量,类中的函数称为类的方法或者成员函数。
struct也可以定义类,struct中也可以定义函数。
定义在类中的成员默认为inline。
2.访问限定符
C++有一种实现封装的方式,用类将对象的属性与方法结合在一起,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
public修饰的成员在类外可以直接被访问,protected和private修饰的成员在类外不能直接被访问。
访问权限作用域从该访问限定符出现的位置开始知道下一个访问限定符或者}出现为止。
class定义成员没有被访问限定符修饰默认private,struct默认为public.
一般成员变量都会被限制为private/protected,需要给别人使用的成员函数为public
3.类域
类定义了一个新的作用域,类的所有成员都在类的作用域中,在类外定义成员时,需要使用::作用域操作符指明成员属于哪个类域。
类域影响编译的查找规则,当前域找不到成员就到类域中找。
#include<iostream>
using namespace std;
class stack
{
public:
void init(int n=1);
private:
int* array;
size_t capacity;
size_t top;
};
void stack::init(int n)
{
array=(int*)malloc(sizeof(int)*n);
if(nullptr==array)
{
perror("malloc申请");
return;
}
capacity=n;
top=0;
}
4.实例化
用类类型在物理内存中创建对象的过程,称为类实例化对象。类是对象的一种抽象描述,没有分配空间,用类实例化对象,才会分配空间。一个类可以实例化多个对象,实例化出的对象,占用实际的物理空间,存储类成员变量。
类实例化出的每个对象,都有独立的数据空间,对象中包含成员变量,成员函数并不包含。
函数编译后是一段指令,对象无法存储,这些指令存在于(代码段)。函数指针是一个地址,调用函数被编译成汇编指令[call 地址],编译器在编译链接时找到函数的地址,不是在运行时找,只有动态多态是在运行时找,那么就要存储函数地址。
内存对齐规则:
第一个成员在与结构体偏移量为0的地址处。
其他成员变量要对齐到某个数字(对齐数)的整数倍地址处。(对齐数:编译器默认对齐数与该成员大小的较小值)。VS中默认对齐数是8。
结构体总大小:最大对齐数(所有变量类型最大者与默认对齐数取最小)的整数倍。
嵌套结构体对齐到自己最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数的整数倍(包含嵌套结构体的对齐数)。
class gugu
{
public:
int a;
};
int main()
{
gugu a;
}
没有成员变量的类对象大小是1,为了占位标识对象。
5.this指针
类的成员函数没有关于不同对象的区分,那么d1,d2两个对象调用函数时,函数需要区分访问哪个对象,就要this(隐含的)来解决。
init函数实际上是void init(class* const this,int data),类的成员函数访问成员变量,本质都是通过this访问,this->data=data。
C++规定不能在实参和形参的位置显式的写this指针(编译时编译器会处理),可以在函数体内使用。
class A
{
public:
void Print()
{
cout<<"A:Print()"<<endl;
}
private:
int a;
};A* p=nullptr;
P->Print();
//正常运行
(*p).Print();
//正常运行成员函数存于代码段,不存于对象中,只是调用函数不用解引用空指针
class A
{
public:
void Print()
{
cout<<"A::Print()"<<endl;
cout<<a<<endl;
}
private:
int a;
};A*p=nullptr;
p->Print();
//运行崩溃,访问了空指针中的成员a,解引用了
this指针存在于栈和寄存器,只是函数临时调用参数,不需要持久存储,this指针的值就是对象的地址,对象在存this逻辑矛盾。