目录
1.类的定义格式
1. class为定义类的关键字,Stack为类的名字,{}中为类的主体,注意类定义结束时后⾯分号不能省略。
class Stack
{
}
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数,class关键字定义与结构体非常类似,只不过是比结构体能多定义一个方法 / 成员函数
2. 为了区分成员变量,⼀般习惯上成员变量会加一个特殊标识,在成员变量前面或者后面加 _ 或者 m开头,注意C++中这个并不是强制的,看个人习惯或者要求
class Date
{
public:
void Init(int year, int month, int day)
{
//成员变量
_year = year;
_month = month;
_day = day;
}
};
class Date
{
private:
int _year; // year_ m_year
int _month;
int _day;
};
成员变量只要定义在类里面就可以,没有其他限制
3. C++中struct也可以定义类,C++兼容C中struct的用法,同时struct升级成了类,明显的变化是
struct中可以定义函数,⼀般情况下我们还是推荐用class定义类
Struct Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
};
class与struct的区别是 :class的默认访问限定符是私有的,而struct的默认访问限定符是公有的
4. 定义在类里面的成员函数默认为inline(内联函数)
2.访问限定符
1. 是C++的⼀种实现封装的方式,用类将对象的属性与方法结合在⼀块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用
2. public(公有)修饰的成员在类外可以直接被访问;protected和private(受保护的/私有)修饰的成员在类外不能直接被访问,protected和private是⼀样的,以后继承章节才能体现出他们的区别
3. 访问权限作用域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为止,如果后面没有访问限定符,作用域就到 }即类结束
#include<iostream>
using namespace std;
class Stack
{
//公有
public:
// 成员函数
void Init(int n = 4);
int a = 0;
//私有
private:
// 成员变量
int* array;
size_t capacity;
size_t top;
};
上面的代码的访问权限作用域就是从 public到private之间的距离,如果没有private的话那么此代码的访问权限作用域就是从public到 }; 结束
4. class定义成员没有给访问限定符修饰时默认为private(私有),struct默认为public(公有)
5. ⼀般成员变量都会被限制为private/protected(私有/受保护的),需要给别⼈使用的成员函数会放为public(公有)6.访问限定符可以出现多次,但是实际中一般只会出现一对public和private
3.类域
1. 类定义了⼀个新的作用域,类的所有成员都在类的作用域中,在类体外定义成员时,需要使⽤ :: 作用域操作符指明成员属于哪个类域
2. 类域影响的是编译的查找规则,下面程序中Init如果不指定类域Stack,那么编译器就把Init当成全局函数,那么编译时,找不到array等成员的声明/定义在哪里,就会报错指定类域Stack,就是知道Init是成员函数,当前域找不到的array等成员,就会到类域中去查找
// 声明和定义分离,需要指定类域
void Stack::kiana
{
int a = 12;
}
int main()
{
st.kiana();
return 0;
}
4.类的实例化
1. 实例化:用类创建一个对象的过程,称为类的实例化
int main()
{
// Date类实例化出对象d1和d2
Date d1;
Date d2;
d1.Init(2024, 3, 31);
d1.Print();
d2.Init(2024, 7, 5);
d2.Print();
return 0;
}
2. 类是对象进行的⼀种描述,是⼀个模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只是声明不开空间,用类实例化出对象(定义)才会分配空间
声明和定义(实例化)的区别就是声明不开空间,定义(实例化)开空间
3. ⼀个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量
打个比方:类实例化出对象就像现实中使⽤建筑设计图造房子,类就像是设计图,而实例化就像是用设计图修建出了房子
同样类就像设计图⼀样,不能存储数据,实例化出的对象分配空间
#include<iostream>
using namespace std;
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
// 这⾥只是声明,没有开空间
int _year;
int _month;
int _day;
};
int main()
{
// Date类实例化出对象d1和d2
Date d1;
Date d2;
d1.Init(2024, 3, 31);
d1.Print();
d2.Init(2024, 7, 5);
d2.Print();
return 0;
}
5.对齐规则
C++的对齐规则和C语言的对齐规则一模一样
1. 第⼀个成员在与结构体偏移量为0的地址处
2.其他成员变量要对⻬到某个数字(对齐数)的整数倍的地址处
3.注意:对齐数 = 编译器默认的⼀个对齐数 与 该成员大小的较小值
4.VS中默认的对齐数为8
5.结构体总大小为:最大对齐数(所有变量类型最⼤者与默认对齐参数取最小)的整数倍
6.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
// 计算⼀下A/B/C实例化的对象是多⼤? 8个字节
class A
{
public:
void Print()
{
cout << _ch << endl;
}
private:
char _ch;//1
//中间间隔3个字节
int _i;//4
};
class B //一个字节
{
public:
void Print()
{
//...
}
};
class C //一个字节
{};
这段代码虽然B和C里面没有内容,但是大小都为一个字节,因为一个字节都没有就表示没有开辟过空间,无法证明存在过
6.this指针
1. C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成
2. 编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this指针
比如Date类的Init的真实原型为:
void Init(Date* const this , int year, int month , int day)
但是我们不能显示的写出来,因为他是隐含的,我们不能抢了编译器的活。但是我们可以直接在类里面用
3. 类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值
this->_year = year;
4. C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理),但是可以在函数体内显示使用this指针
this指针的特性总结:
1. this指针的类型:类类型* const
2. 只能在“成员函数”的内部使用
3. this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针
4. this指针是成员函数第一个隐含的指针形参
this指针一般默认存储在栈里
未完待续~