类与对象初步认识
一、面向对象和类
面向过程和面向对象的认识
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
C++基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
类的定义
在面向对象的程序中,除主函数外,其他函数基本上都是出现在“类”中的,只有通过类才能调用类中的函数。类是对象的抽象,对象是类的具体体现
- 类:对实体(对象)进行描述,功能、属性等,是一种自定义类型
- 对象:现实存在的事物,用类创建出来的便来的变量
定义格式:
//这里用struct或者class定义都可以
class className
{
//类体
//包括成员变量和成员函数
};
类的两种定义方式
1.生命和定义全部放在类中
Student.cpp
class Student
{
char* _name;
char* _gender;
int _age;
int _score;
void ShowInfo()
{
cout << _name << " " << _age << endl;
}
};
函数在类中定义,编译器可能会将其当成内联函数展开,一般情况下会在成员变量前加"_",区分成员变量与成员函数的形参。
2.声明放在头文件中,定义放在源文件中
Student.h
#pragma once
class Student
{
char* _name;
char* _gender;
int _age;
int _score;
void ShowInfo();
};
Student.cpp
#include"Student.h"
#include<iostream>
using namespace std;
//函数的定义
void Student::ShowInfo()
{
cout << _name << " " << _age << endl;
}
注意:成员函数放在类外定义,要在成员函数前加类名及作用域限定符,如:“Student::” 。
二、类的访问限定符及封装
面向对象的三大特性:封装、继承、多态
封装:将数据和数据的操作方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口和对象进行交互。(电脑机箱的例子)
访问限定符
- public(共有)可以在类外直接访问
- protected(保护)不能在类外访问,与private的区别在继承中体现
- private(私有)不能在类外访问
class Student
{
//private修饰成员变量,只能在类内访问
private:
char* _name;
char* _gender;
int _age;
int _score;
//public修饰成员函数,可以在类外访问
public:
void ShowInfo()
{
cout << _name << " " << _age << endl;
}
};
int main()
{
Student s1;
s1.ShowInfo();
system("pause");
return 0;
}
几点注意事项
- 访问权限作用域从该访问权限限定符出现的位置直到下一个访问限定符出现为止
- class的默认访问权限为private,struct的默认访问权限为public(因为struct要兼容C语言)
三、类对象模型
- 类是一个模型,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间
- 一个类可以实例化出来多个对象,实例化出来的对象占用内存空间
类和对象的大小
- 对象的大小只包含成员变量
- 类的大小就是类中成员变量大小的和,进行内存对齐,计算方式与结构体内存对齐相同,空类较为特殊,编译器给空类一个字节来唯一标识类,避免不同对象在同一个地址加粗样式。
通过下面的程序验证类和对象的大小
#include<iostream>
using namespace std;
//日期类
class Date
{
public:
void Print()
{
cout << _year << " " << _month << " " << _day << endl;
}
void Init(int year,int month,int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
class A1
{
void Func();
};
class A2
{
void Func();
};
int main()
{
Date d1;
d1.Init(2022, 7, 28);
d1.Print();
cout << sizeof(Date) << endl;
cout << sizeof(d1)<<endl;
cout << sizeof(A1) << endl;
cout << sizeof(A2) << endl;
system("pause");
return 0;
}
打印结果:
四、this指针
概念
在每个成员函数中都包含一个特殊的指针,这个指针就是this指针。this指针是指向本类对象的指针,它的值是当前被调用的成员函数所在的对象的起始地址。
调用Func()函数打印隐藏的this指针地址:
class A1
{
public:
void Func()
{
//打印this指针地址
cout << this << endl;
}
};
this指针特性
- this指针的类型:类类型* const,如:Date *const this
- 只能在“成员函数”的内部访问
- this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
- this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
关于this的两个问题
- this指针存在哪里
this指针会因编译器不同而有不同的放置位置,可能是栈,也可能是寄存器 - this指针可以为空吗?
可以,但是在访问对象的成员变量时会崩溃(访问空指针),成员函数中没有访问成员变量则不会崩溃
通过这个程序将this指针赋值为空
class A1
{
public:
void Func()
{
cout << "Func" << endl;
}
};
int main()
{
A1 a;
A1* pa =&a;//pa为指向a对象的指针
pa = nullptr;//对pa赋值为空
//这里的pa作为Func函数的参数传递,所以为空不会报错,即传递实参给this
//并不是访问空指针
pa->Func();
system("pause");
return 0;
}
编译器编译类的顺序
- 先识别类名
- 识别类中的成员变量
- 识别类中的成员函数
- 对成员函数进行改写