类class
类的定义:class为类定义的关键字,跟struct非常的相似,区别在与class可以定义成员函数。
注意为了区别成员变量,一般习惯上会将成员变量会加上一个特殊标识,这并不是强制的。
c++中的struct也可以定义类,c++兼容c中struct的用法,同时struct升级成了类,明显的变化是struct中也可以定义函数吗,但是还是推荐使用class定义类。
定义在类中的成员函数默认为inline。
访问限定符
c++实现了一种封装的方式,用类将对象的属性和方法结合在一块,让对象更加完美,通过访问权限选择性的将其接口提供给外部的用户使用。
限定访问符有三种:public,pravite,protected:
puclic修饰的成员在类外可以直接被访问,protected和pravite修饰的成员不能在类外直接访问。
访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现为止,如果后面没有访问限定符就到}为止。
class中定义的成员如果没有被访问限定符修饰就默认为pravite。struct中定义的成员默认为public。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class stack//一般对于成员函数是public,成员对象是private
{
//成员函数
public:
void init(int n=4)
{
arr = (int*)malloc(sizeof(int) * n);
if (arr == nullptr)
{
perror("malloc");
return;
}
capacity = n;
top = 0;
}
void push(int x)
{
if (top == capacity - 1)
{
int*tmp= (int*)realloc(arr, sizeof(int) * capacity * 2);
if (tmp == nullptr)
{
perror("realloc");
return;
}
arr = tmp;
capacity *= 2;
}
arr[top] = x;
top++;
}
int showtop()
{
return arr[top - 1];
}
void destroy()
{
free(arr);
arr = nullptr;
capacity = 0;
top = 0;
}
//成员变量
private:
int* arr;
size_t capacity;
size_t top;
};
//类名就是类型
int main()
{
stack st1;//stack就是一个类型名
st1.init();
st1.push(1);
st1.push(2);
cout <<st1.showtop()<< endl;
st1.destroy();
return 0;
}
类域
命名空间域跟类域都不会影响生命周期。
类定义了一个新的作用域,类的所有成员都在类的作用域中,在类体外定义成员时,需要使用操作符::指明成员属于哪个类域。
类域影响编译器的查找规则,如果在函数定义的时候不指定类域,在寻找声明的时候就会在全局中找。
类的实例化
在class中的变量是一个声明。对于声明跟定义的区别就是是否分配了空间。
对于类型中的变量的定义是随着对象来定义的。这个过程叫做类实例化出对象。一个类可以实例化出无数对象,类就是一个类型,而不是一个实际的存在。可以用类实例化出对象,然后再对对象进行初始化。其实你在用类定义你的对象时就已经给这个对象开辟好了空间,然后对对象进行初始化就好了。
class person
{
public:
int age;
int hight;
};
int main()
{
person ve;
ve.age = 10;
cout << ve.age << endl;
}
对象的大小
对象的大小在计算的时候只用计算成员变量的大小,计算方式跟结构体类似,遵循内存对齐的规则。
由于不同的对象调用的成员函数是一样的,所以没有必要将成员函数的地址存到类中,事实上函数指针是不需要存储的,函数指针是一个地址,调用函数被编译成汇编指令[call地址],其实在编译链接时就要找到函数的地址,不是在运行的时候找,只有动态多态是在运行的时候找,就需要存储函数地址。
对于没有成员的类的对象,大小为1byte,占位,不存储有效数据
内存对齐规则:
1.第一个成员在与结构体偏移量为0的地址处。
2.其他成员变量要对齐到(对齐数)的整数倍的地址处。注意:对齐数=编译器默认的一个对齐数跟该成员大小的较小值。
3.vs中的默认对齐数是8.
4.结构体的总大小为:最大对齐数(所有成员变量类型最大者跟默认对齐数取小)的整数倍。
5.如果嵌套了结构体的话,嵌套的结构体对齐到自己的最大对齐数的正数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的最大对齐数)的整数倍。
这里就要提到为什么要内存对齐:对于内存的读取我们不是一个字节一个字节读取的,而是多个字节读取,如果没有内存对齐会产生一个数据要读两次还要拼起来的情况导致效率下降,所以牺牲一点空间换取效率。
this指针
想必大家都有一个疑惑就是:明明调用的是同一个成员函数但是执行却能根据不同的对象的成员进行操作,这是怎么做到的呢?
其实编译器编译后,类的成员函数都会默认在形参的第一个位置增加一个当前类类型的指针,叫做this指针:(类名*)const this
类的成员函数访问成员变量,本质都是通过this指针访问的。每一个成员函数第一个形参都是隐形的指向该对象的this指针。在通过对象调用成员函数时传的参数第一个时隐形的&对象。
c++规定不能再在实参和形参的位置显示的写this指针。但是可以在函数体内显示使用this指针,所以在函数体内使用this调用类。
这里一点要注意一下:对于类中的public的函数的调用其实跟普通的函数没什么区别,对于成员函数的指针是在编译时确定的,没有存到对象中如果函数中用到了对象中的成员变量其实是通过隐藏的this指针找到的,如果没有用到成员变量,那么调用这个函数本身是跟对象没有关系的,也就是说可以是一个空的对象。
c++与c语言stack的差异
首先c++是面向对象的语言,面向对象的三大特征:封装,继承,多态。
对于栈的实现,c++可以用类将stack的数据和方法都放在一起,并且可以使用访问限定符限定。而c语言则是数据是数据方法是方法。对于c++不能直接访问对象中的数据,可以更好的保护和管理。