目录
前言
1. 面向对象和面向过程
2. 类的引入
3. 类的定义
3.1 类的定义方法
4. 类的访问限定符和封装
4.1 访问限定符
4.2 封装
5. 类的作用域
6. 类的实例化
7. 类对象模型
7.1 类对象的大小
8. this指针
在初学C语言时,想必大家都听说过 “ 面向过程 ” 和 “ 面向对象 ”,C语言是面向过程的编程语言,而我们常用的C++,Java、python都是面向对象的编程语言,那什么面向过程,什么又是面向对象?它们有什么区别呢?那么今天我们就来了解一下C++中的类和对象。
C语言是面向过程的编程语言,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决。有人以洗衣服为例,进行了形象的比喻,把C语言实现一个功能比作洗衣服,那么它的过程如下边的流程一样:
C++是基于面向对象的编程语言,它关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
可分为四个对象:人、衣服、洗衣机、洗衣液
洗衣服整个过程是由四个对象交互完成。
在C语言中:
结构体中只能定义变量
而在C++中:
结构体内不仅可以定义变量,也可以定义函数
比如:
struct Data
{
void Init(int year,int month,int day)//成员函数
{
_year = year;
_month = month;
_day = day;
}
void Print()//成员函数
{
cout << _year << _month << _day << endl;
}
int _year;
int _month;
int _day;
};
C语言中的结构体也可以被称为类
可以说是一个极简的类
C++中兼容C语言struct所有用法
C++ 中将struct升级成了类
C++更喜欢用class来代替
class MyClass
{
// 类的成员和函数声明
}; //注意分号不能省略
类中的变量称为类的属性(成员变量)
类中的函数称为类的方法(成员函数 )
成员函数在类中定义:
class Data
{
public:
void Print()
{
cout << _year << _month << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
成员函数定义在类中,会被当作内联函数处理
注意:
//Date.h
class Data
{
public:
void Print();
private:
int _year;
int _month;
int _day;
};
//Date.cpp
void Date::Print()
{
cout << _year << _month << _day << endl;
}
命名建议:
大家可能有疑惑,为什么我要在变量前加 “_”
比如:
void Init(int year,int month,int day)
{
year = year;
month = month;
day = day;
}
在写一些初始化函数时,将值赋给类中的变量
这样写容易分不清楚哪个是成员变量
为了便于区分,建议这样写:
void Init(int year,int month,int day)
{
_year = year;
_month = month;
_day = day;
}
封装时不可能将所有的成员都让外部用户使用
访问限定:
选择性的将其接口提供给外部的用户使用
限定符说明:
C++中struct和class的区别是什么?
为了便于给外部用户使用于是就引入了封装的概念
封装本质上是一种管理,让用户更方便使用类
类的作用域体现在成员函数的声明和定义分离
在类的外边定义成员函数时需要指定域
//Date.h
class Data
{
public:
void Print();
private:
int _year;
int _month;
int _day;
};
//Date.cpp
void Date::Print()//Date::域作用限定,限定成员函数Print()属于类Date
{
cout << _year << _month << _day << endl;
}
类的实例化,就是创建对象的过程
类是对对象的描述,并没有分配实际的空间
int main()
{
Date.year=2023;//报错
return 0;
}
Date类没有实际存储空间
类就像是设计图,可以通过图纸建造多个房子
class Data
{
public:
void Print()
{
cout << _year << _month << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
类中既可以有成员变量,也可以有成员函数,要如何计算?
上述类的大小为12
在类的实例化中提到过:
实例化出的对象 占用实际的物理空间,存储类成员变量
总结:
类大小计算和结构体大小计算相同(不考虑函数)
结构体大小计算详细可见:从头开始:自定义类型入门指南(结构体、位段、枚举、联合)
那空类或者说只有成员函数的类大小是多少
class A//大小1字节
{};
class B//大小1字节
{
public:
void f2() {}//成员函数在独立的空间
};
为什么是占一个字节?
不同的对象调用同一函数,函数如何区分?
class Data
{
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(2023,10,24);
Date d2(2022,10,24);
d1.Print();//调用相同的print函数(没用参数)输出结果不同
d2.Print();
return 0;
}
为了便于区分,于是引入了this指针的概念。
所以真实调用是这样的:
void Print(Date* this)
{
cout << this->_year << this->_month << this->_day << endl;
}
虽然this指针在参数列表里没有显示,但是可以在类里显示使用
面试题:
this指针存在哪里?
this指针存在栈帧里(VS中,存到了寄存器ecx中)
this指针可以为空吗?
我们以下面的代码为例:
代码一:
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();//这里并不是传p的地址过去,传的是p
return 0;
}
代码一可以正常运行
为什么?
前边提到,成员函数不在对象里边,所以找Print函数时并不需要通过A的指针来访问,并且Print函数内部也没有访问类的成员变量(没用使用this指针)。这里p的作用仅仅是说明Print函数是A里的成员函数,所以并不会访问到空地址。
代码二:
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
return 0;
}
代码二在运行时会运行崩溃
代码一中也做了解释:
成员函数不在对象里边,找PrintA函数时并不需要通过A的指针来访问 ,但是在执行PrintA函数时使用了this指针访问成员变量,这里的this指针是空指针(无效地址),在访问时就会访问冲突,所以会造成运行崩溃(运行错误)。
由此我们可以总结出:
this指针可以为空,但要看它是否访问成员变量,如果通过this指针访问了成员变量就会运行崩溃,如果没有访问那也可以正常运行。
好了以上便是本期全部内容,希望对你有所帮助,最后感谢阅读!