不要觉的自己很没用,其实你还可以给家人带来温暖,比如爸妈看到你就来火
目录:
一、面向过程和面向对象初步认识
二、类的引入
三、类的定义
四、类的访问限定符及封装
1.访问限定符
2.封装
五、类的作用域
六、类的实例化
七、类的对象大小的计算
1.类对象的存储方式猜测
2.结构体内存对齐规则
八、类成员函数的this指针
1.this指针的作用
2.this指针的特性
3.面试题练习
九、完结撒❀
前言:
对于类和对象的讲解一共划分为3篇,这是第1篇入门篇学习,更适合小白宝宝的体质
–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–
一、面向过程和面向对象初步认识
二、类的引入
typedef int DataType;
struct Stack
{
void Init(size_t capacity)
{
_array = (DataType*)malloc(sizeof(DataType) * capacity);
if (nullptr == _array)
{
perror("malloc申请空间失败");
return;
}
_capacity = capacity;
_size = 0;
}
void Push(const DataType& data)
{
// 扩容判断 此处省略
_array[_size] = data;
++_size;
}
DataType Top()
{
return _array[_size - 1];
}
void Destroy()
{
if (_array)
{
free(_array);
_array = nullptr;
_capacity = 0;
_size = 0;
}
}
DataType* _array;
size_t _capacity;
size_t _size;
};
int main()
{
Stack s;
s.Init(10);
s.Push(1);
s.Push(2);
s.Push(3);
cout << s.Top() << endl;
s.Destroy();
return 0;
}
可以看到在上面代码中,结构体stack里面定义了变量:
三、类的定义
类的定义如下:
class className
{
// 类体:由成员函数和成员变量组成
}; // 一定要注意后面的分号
在后序工作中一般使用第二种定义方式
在上面演示图片中的代码,细心的同学可能已经注意到了,我们定义人的结构体变量名前面都加上了一个_,其实这是为了防止变量名冲突混淆含义而定义的
举例如下:
class Data
{
public:
//我们看这个函数会感觉很僵硬
void Init(int year, int month, int day)
{
//这里的year、month、day到底是成员变量还是函数形参
year = year;
month = month;
day = day;
}
private:
int year;
int month;
int day;
};
上面代码无法区分Init函数中谁是形参谁是变量
所以我们在实际中一般这样写:
class Data
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
其他命名方式都可,这主要看公司要求,一般都是加一个前缀加一个后缀标识区分就行。
上面定义结构体中我们使用了public和private,这是类的访问限定符,下面我们对其进行间接。
四、类的访问限定符及封装
1.访问限定符
class Data
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
上面代码,类中共有域为public到private的范围,私有域为private到类结束为止
那么我们在主函数中创建类变量即可访问到函数Init,但是访问不到类的成员变量,因为成员变量范围在私有域内,所以只能在类里面才能被访问
class Data
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Data da1;
da1.Init(2024, 4, 7);//直接访问
da1.Init(_day);//直接报错
return 0;
}
之前看到的一道【面试题】:
2.封装
五、类的作用域
比如下面代码:
class Person
{
public:
void PrintPersonInfo();
private:
char _name[20];
char _gender[3];
int _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
cout << _name << " "<< _gender << " " << _age << endl;
}
六、类的实例化
还拿上面代码举例:
class Data
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Data da1;
da1.Init(2024, 4, 7);//直接访问
da1.Init(_day);//直接报错
return 0;
}
类中的成员变量_year,_month,_day都是对其进行的声明,并没有开辟真正的空间,只有当定义出类变量da1时才会真正对类中的成员变量开辟空间,这就是类的实例化。
七、类的对象大小的计算
class Person
{
public:
void PrintPersonInfo();
void SetPersonInfo();
private:
char _name[20];
char _gender[3];
int _age;
};
1.类对象的存储方式猜测
··· 对象中包含类的各个成员
··· 代码只保存一份,在对象中保存存放代码的地址
··· 只保存成员变量,成员函数存放在公共的代码段
问题:对于上述三种存储方式,那计算机到底是按照那种方式来存储的?
我们再通过对下面的不同对象分别获取大小来分析看下
class A1 {
public:
void f1(){}
private:
int _a;
};
// 类中仅有成员函数
class A2 {
public:
void f2() {}
};
// 类中什么都没有---空类
class A3
{};
分别计算每个类的大小可以直到
sizeof(A1):4 sizeof(A2) : 1 sizeof(A3) : 1
A1中有一个成员函数和成员变量构成,总大小为4个字节
A2只有一个成员函数组成,总大小为1个字节
A3为空类,里面什么都没定义,总大小为1个字节
空类和只有一个成员函数的类大小相等都为1个字节,说明类的空间大小并没有计算成员函数的大小
那么我们就可以推测出
2.结构体内存对齐规则
下面我们再回顾学习一下结构体的内存对齐规则
八、类成员函数的this指针
1.this指针的作用
我们先看一下下面代码:
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;
d1.Init(2022,1,11);
d2.Init(2022, 1, 12);
d1.Print();
d2.Print();
return 0;
}
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
//void Print()
void Print(Data* const this)
{
//cout << _year << "-" << _month << "-" << _day << endl;
cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
}
private:
int _year; //年
int _month; //月
int _day; //日
};
int main()
{
Date d1, d2;
d1.Init(2022, 1, 11);
d2.Init(2022, 1, 12);
d1.Print();
d2.Print();
return 0;
}
上面代码中this指针所在位置就是编译器自己进行处理的操作,因为是隐含的this指针,形参和实参的位置不能显示写,编译器会自行处理,但是this指针是可以在类里面显示着进行使用的。
我们需要知道的是函数体是进行对象区分是通过this指针自动将成员变量的地址传递了过去,当作函数的形参进行了使用。
2.this指针的特性
3.面试题练习
下面我们来看两道【面试题】
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
答案:C、正常运行
题解:定义出的类指针变量赋值为空指针,之后访问Print成员函数,这里我们就要清楚程序是如何进行Print函数的访问的——通过this指针,而我们只是向Print函数传了一个空指针作为形参而已,并且我们并没有对空指针进行访问,所以不会出现报错,所以程序最终进入Print函数打印出了Printf()字符串。
根据下面代码选择ABC中一个选项:
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
void PrintA()
{
cout<<_a<<endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
return 0;
}
答案:B
题解:上面代码中PrintA函数里cout<<_a<<endl;在编译运行时真正的运行的代码为:cout<<this->_a<<endl;而这里的this指针为空指针,对空指针访问成员变量最后程序就会运行崩溃。
九、完结撒❀
如果以上内容对你有帮助不妨点赞支持一下,以后还会分享更多编程知识,我们一起进步。
最后我想讲的是,据说点赞的都能找到漂亮女朋友❤