1.C语言中,结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。但是C++中一般定义类使用class
2.类包含两部分:成员变量、成员函数(可以在类中定义成员函数)
要点:
(1)在class内部实现的函数默认为inline函数
(2)在类(class)中的成员函数,没有加访问限定符,默认为私有,若是struct,则默认为共有
(3)函数的声明与函数体可以写在一起,也可以分开写,若是分开写,函数体在类外写需要指定域名
(4)成员变量定义为私有,是变量声明,不是变量的定义,因为没有给变量开辟空间
//类 -定义出一个新的类型
//类由两部分构成:成员变量(属性)、成员函数(做的行为)
//C++中的struct兼容C的所有用法,同时把struct升级成类
//xx.h
//在类设计中,一般想给别人(成员函数)访问的定义为共有(public)
//不想给别人访问的就定义为private/protected
class Stack //class也可以换成struct
{
void Pop()
{
}
public: //未加访问限定符,默认为私有
void Init(int initSize = 4);//函数声明,也可直接和函数体写一起
void Push(STDataType x);
protected:
STDataType* a; //成员变量在这里是声明(未开辟空间)
int size;
int capacity;
};
//xx.cpp
void Stack::Init(int initSize )
{
a = (STDataType*)malloc(sizeof(STDataType)*initSize);
size = 0;
capacity = initSize;
}
void Stack::Push(STDataType x) //成员函数在外面需要指定域名
{
//..
a[size] = x;
size++;
}
int main()
{
Stack st;
st.Init();
st.Push(1);
st.Push(2);
st.Push(3);
st.Pop(7); //不能调用,class默认为私有,struct才默认为共有
return 0;
}
3.访问限定符
(1)public修饰的成员在类外可以直接被访问
(2)protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
(3)访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
(4)class的默认访问权限为private,struct为public(因为struct要兼容C)
4.注意:C++中struct和class的区别
C++需要兼容C语言,所以C++中struct可以当成结构体去使用。另外C++中struct还可以用来定义类。和class是定义类是一样的,区别是struct的成员默认访问方式是public,class是的成员默认访问方式是private。
5.类的实例化
用类类型创建对象的过程,称为类的实例化
例如:
Stack st; //st就是一个对象,利用Stack创建st的过程就是类的实例化
Stack st1; .//可以创建多个对象 st,st1……
(1)类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它
(2)一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
6.类对象大小的计算
要点:
(1)类对象存储方式:只保存成员变量,成员函数存放在公共的代码段(因为创建出来的对象调用的是相同的成员函数,把成员函数放在公共代码段,显示是公用的)
(2)空类:没有成员变量或只有成员函数的类叫做空类
(3)空类的字节大小占:1,1不是为了存储数据,是为了占位,表示对象存在过
计算大小:
class A1
{
public:
void f1(){}
int a;
};
//类中仅有成员函数
class A2
{
public:
void f2() {}
};
//空类
class A3
{};
int main()
{
cout << sizeof(A1) << endl;// 4,不用看成员函数
A1 aa;
aa.f1();
//大小是1.不是为了存储数据,表示占位,表示对象存在过
A2 a2;
cout << sizeof(a2) << endl; //1
A3 a3;
cout << sizeof(a3) << endl; //1
return 0;
}
结构体内存对齐规则:
(1)第一个成员在与结构体偏移量为0的地址处。
(2)其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS中默认的对齐数为8
(3)结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
(4)如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
进行内存对齐:提高效率
7.this指针
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
this指针的特性:
(1) this指针的类型:类类型* const
(2)只能在“成员函数”的内部使用
(3)this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
(4)this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递
class Date
{
public:
//编译会增加一个隐含的参数:void Init(Date* this,int year, int month, int day)
//1.this指针式隐含的,是编译器加的,我们不能显示的在调用和函数定义中加
//2.可以在成员函数中使用
//3.this存在于栈中,不同编译器不同,VS是使用ecx寄存器存储,传参
void Init(int year, int month, int day) //私有的成员变量通过共有的成员函数进行初始化
{
//检查日期的合法性
//成员函数中,成员前面编译器会自动加this->,看自己想加不加
this->_year = year;
this->_month = month;
this->_day = day;
}
private:
//凡是成员变量,建议 命名风格区分
int _year;
int _month;
int _day;
};
int main()
{
//哪个对象去调用成员函数,成员函数中访问的就是哪个对象中的成员函数,是通过this指针做到的
//所以调用相同的函数,值不一样,本质是其地址不一样
Date d1;
d1.Init(2021, 5, 24); //d1.Init(&d1,2021,5,24),调用时会传对象的地址
Date d2;
d2.Init(2021, 5, 25);
return 0;
}
this指针的一个应用:
// 1.下面程序能编译通过吗? 可以
// 2.下面程序会崩溃吗?在哪里崩溃
class A
{
//成员函数中接收到的this是空指针
public:
void PrintA()
{
cout << _a << endl; //进行了解引用,访问_a :this->_a,出现错误
}
void Show()
{
cout << "Show()" << endl; //没有解引用
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA(); //空指针 ,会出现错误
//p->Show()等等这些函数,这里没有对p这个指针进行解引用
//因为Show()等成员函数的地址没有存到对象里面(对象里面存的是成员变量)
//成员函数的地址是存储在公共代码段
p->Show(); //正常运行
}
要点:
(1)类定义不同的对象去初始化对象,调用的是相同的初始化函数,不同对象去调用函数是利用this指针去传递自己的地址调用属于自己的函数
在初始化时,本该是
Date d1;
d1.Init(&d1,2021,5,24) //调用时会传对象的地址
我们写成了
Date d1;
d1.Init(2021, 5, 24); //d1.Init(&d1,2021,5,24),调用时会传对象的地址
(2)this指针是隐式的,我们不能在函数定义时和调用时加上this(所以我们在(1)写成了以上形式),可以在成员函数中加上
(3)this指针存在的位置:在栈上,因为this是形参,形参和局部变量都存在栈上面