类和对象
一.类和对象的定义
1.struct 类名{数据和数据相关的函数};(类外可访问)
struct定义的类,默认访问权限为public
2.class 类名{所有的成员};(类外不可访问)
class定义的类,默认访问权限为private
class Student{
void SetStudentInfo(const char* name, const char* gender, int age){
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
void PrintStudentInfo(){
cout << _name << " " << _gender << " " << _age << endl;
}
char _name[20];
char _gender[3];
int _age;
};
int main(){
Student Stu;
stu.SetStudentInfo("abc", "nan", 30);
stu.PrintStudentInfo();
cout << stu._gender <<endl;
}
可以声明在.h里面,定义在.cpp里面
//.h文件-----保存在person.h中
class Person{
public:
void showInfo();
}
//.cpp文件-----保存在person.cpp中
//函数在类外定义,需要加类的作用域
#include "person.h"
void person::showInfo(){
cout << _name << "-" << _sex << "-" << _age << endl;
}
函数在类外定义,需要加类的作用域
void person::showInfo(){
cout << _name << "-" << _sex << "-" << _age << endl;
}
①访问类成员
- 通过"."的形式
- 如果是真真,通过"->"的形式
//this函数用于区分所要输入的数据,相当于隐式的函数形参(this指针在不做解引用的情况下可以为空)
class Date{
void Display(){
cout << _year << "-" << _month << "-" << _day << endl;
A a;
}
void SetData(int year, int month, int day){
this -> _year = year;
_month = month;
_day = day;
}
int _year;
int _month;
int _day;
};
int main(){
Date d1, d2;
d1.SetData(2018, 5, 1);
d2.SetData(2018, 5, 2);
}
3.类的大小 == 类实例化后对象的大小
按照结构体的规则计算
- 成员函数不占对象的空间
- 不含成员变量
- 空类/不含成员变量的类为1字节
4.类的实例化(定义一个类的过程)
类中有6个默认成员函数:
①构造函数(可以重载)-----初始化一个对象内容的函数,不是创建对象(编译器在创建对象时,自动调用构造函数)
//默认构造:无参构造、全缺省构造
//如果不写构造函数,编译器自动生成一个无参的构造函数
//调用无参函数
Data d;
//不能显示调用构造函数
d.Data(2020, 1, 2); //报错
//不能有多个默认构造函数
//默认构造函数可以为全缺省函数
//无参/带参的构造函数中隐含了this指针,在函数中调用过程中可以用this指针访问里面的数据,也可以不用
初始化列表-----:
以下三种情况必须在定义的时候初始化(即使用初始化列表)
- const int _n; //const修饰的变量
- int& _ref; //引用类型
- Time _t; //没有默认构造函数(不用参数调用)的类
Date(int year, int month, int day){
:_year(year)
,_month(month)
,_day(day)
}
初始化列表的运行顺序
由变量声明的顺序决定其运行顺序
class A
{
public:
A(int a) //初始化(定义)
:_a1(a)
,_a2(_a1)
{}
void Print() {
cout<<_a1<<" "<<_a2<<endl;
}
private:
int _a2; //声明
int _a1;
}
int main() {
A aa(1);
aa.Print();
}
因为是先声明_a2,再声明_a1,所以,初始化时,_a2需要使用_a1来使用,_a1此时还没有初始化,_a1为随机值,所以_a2也为随机值
正常的初始化列表 VS 匿名
int main(){
A aa1(1); //他的生命周期在main函数域
A(2); //匿名对象,他的生命周期在这一行
}
int main(){
A aa1(1); //他的生命周期在main函数域
A(2); //匿名对象,他的生命周期在这一行
Solution s;
cout << s.StrToInt("1234") << endl; //
//这个调用对象其他地方都不用,就这一行用,那么就可以用匿名对象
cout << Solution().StrToInt("1234") << endl; //这两行一样的效果
return 0;
}
初始化列表 VS 正常的初始化
- 初始化列表是在定义时直接进行初始化,而正常的初始化是先给对象随机值,再进行初始化的过程
构造函数的多种使用方式
A aa1(1);
A aa2 = 2; //隐式类型转换,结果调用析构函数
//先构造一个A(2)匿名临时对象,再用这个临时对象去拷贝构造aa2
//编译器将这个过程优化了,直接调了构造函数,不构造A(2)临时对象了
匿名临时对象的应用
class Solution{
public:
int n = str.Size();
if(n < 1)
return 0;
int flag = 1;
int ret = 0;
}
int main(){
//1
string str(“1234”);
cout << Solution().StrToInt(str) << endl;
//2
cout << Solution().StrToInt(string("1234")) << endl;
//3
cout << Solution().StrToInt("1234") << endl;
}
explicit-----不允许隐式类型转换发生
explicit A(int a)
:_a(a)
{}
②析构函数(没有参数,没有返回值,不能重载)-----完成类的资源清理
- 函数生命周期结束时,自动调用析构函数
//对象销毁的时候,编译器自动调用析构,销毁资源(在栈空间上的数据)
//不显示定义析构,编译器会自动生成默认的析构函数
函数名:在类名前加~
~SeqList(){
if(_pData){
free(_pData); //释放堆上的空间
_pData = NULL; //将指针置为空
_capacity = 0;
_size = 0;
}
}
③拷贝构造
调用拷贝构造
Date date(2021, 2, 2);
Date copy(date);
Date(int year = 1, int month = 1, int day = 1){
_year = year;
_month = month;
_day = day;
}
//拷贝构造(编译器自己默认带的是浅拷贝-----只复制对象,不一定复制内容)
//若没有显示定义,会自动生成
Date(const Date& d){
_year = d._year;
_month = d._month;
_day = d._day;
}
int main(){
Date date(2021, 2, 2);
Date copy(date);
}