类与对象(上)
一、类的定义
1.1 类的定义
class ClassName
{
//类体:包含成员函数和成员变量
};
class为定义类的关键字,ClassName为类的名字,类中的元素称为类的成员:类中的数据称为类的属性或是成员变量
类中的函数称为类的方法或是成员函数
二、类的声明与定义
类的声明和定义可以放在一起,也可分开,将声明放在类的头文件.h,将定义放在类的实现文件.cpp中。
三、 类的访问限定符及封装
1、访问限定符的分类
(1)public 修饰的成员在类外可以直接被访问
(2)protacted和private修饰的成员在类外不能被直接访问
(3)class的默认访问权限是private,struct的默认访问权限是public(在C++中struct也可用作定义类的关键字)。
2、封装
面向对象的三大特性:封装、继承、多态
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
五、类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中,在类外定义成员,需要使用作用域解析符::来指明成员是属于哪一个类域的。
class Date
{
public:
//成员函数,公有,类外可直接访问
Date(int year,int month, int day);
Display();
private:
//成员变量,私有,类外不可直接访问
_year;
_month;
_day;
};
void Date::Display()//这里必须指明Display是属于Date这个类域的
{
cout << _year << "-" << _month << "-" << _day << endl;
}
六、类的对象模型
6.1 如何计算一个类对象的大小
计算一个对象的大小只看类的成员变量的大小,不用考虑类的成员函数的大小
#include<iostream>
using namespace std;
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
private:
char _a;
};
int main()
{
A a1;//对象a1中的_a与a2中的不同
A a2;
a1.PrintA();//a1和a2所调的成员函数PrintA是同一个成员函数
a2.PrintA();
//这就是计算对象大小只计算成员变量不计算成员函数的原因
return 0;
}
class A1 {
public:
void f1(){}
private:
int _a;
};//类的大小为4个字节
// 类中仅有成员函数
class A2 {
public:
void f2() {}
};//类的大小为一个字节
// 类中什么都没有---空类
class A3
{};//类的大小为一个字节
一个类的大小,实际就是该类中”成员变量”之和,也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。
6.2 结构体内存对齐的规则
(1) 第一个成员在与结构体偏移量为0的地址处。
(2) 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的对齐数为8,gcc中的对齐数为4
(3) 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
(4) 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是
所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
计算一个结构体的大小
struct A {
char ch;
int a ;
};//结构体的大小为8个字节
内存对齐的意义:是以浪费空间为代价,换取内存访问的效率,cpu在访问内存时是一次读取4个字节,如果没有内存对齐,此时访问int类型变量时时,需访问两次才能读取int类型的变量
七、this指针
7.1 this指针的特性
(1) this指针的类型:类类型* const
const修饰指针:int const* p1;
const修饰指针指向的内容: int* const p2; const int* p3
(2) 只能在“成员函数”的内部使用
(3)this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this
形参。所以对象中不存储this指针。
(4) this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
void Show()
{
cout << "Show()" << endl;
}
private:
int _a;
};
int main()
{
A a;
A* p = nullptr;
p->Show();//编译能通过,运行能通过
A a;
A* p = nullptr;
p->PrintA();//编译能通过,运行不能通过
return 0;
}
注:1、this指针存在栈帧或是exc寄存器中。
2、this是可以为空的,this指针为空时,程序都能正常编译,若不对其进行解引用,则程序能够正常运行。