类和对象——上
目录:
类和对象是很重要的知识点,对于初学者也不容易理解。希望大家多学几遍,搞懂内容,在进一步学习下一步的内容,学习c++就得一步一步来,打好基础,稳定向前。
一、面向过程和面向对象
C语言是面向过程的,关注的是过程,分析求出解决问题的步骤,通过函数调用逐步解决问题。
c++是面向对象的,关注的是对象,将一件事情拆分为不同的对象,靠对象之间交互完成。
二、类的概念
1.类的引用
1.c++兼容c结构体的用法
2.c++把结构体升级成了类,类名就是类型(可以用class代替)。
3.类是一个整体,有成员变量和成员函数,并且位置任意。
4.struct默认公有,class默认私有。
5.类是一个整体,不需要定义在前面或者后面。
2.类的定义
class为定义类的关键字,Classname为类的名字,{}中为类的主体,注意类定义后面分号不能省略。
类主体的内容称为类的成员:类中的变量叫成员变量,函数称为成员函数。
类的两种定义方法:
1.声明和定义全部在类体中。
#include <iostream>
using namespace std;
class PerSon
{
public://公有得
//成员函数:
void person()
{
cout << "姓名:p" << endl;
}
private://私有得
// 成员变量:
char* _name;//姓名
char* _sex;//性别
int _age;//年龄
};
2.类声明放在.h文件中,成员函数定义在cpp文件中,成员函数名前需要加类名::。
类声明和定义分离:
注意:
1.默认在类里面定义的函数,为内联函数(inline),这个由编译器决定是不是内联。
2.正确的用法;长的函数声明和定义分离,短小的函数可以直接在类里面定义(编译器决定内联函数)。
三、类的访问限定符和封装
c++实现封装的方式: 用类将对象的属性和方法结合在一块,让对象更加完善,通过访问限定符选择性的将接口提供给外部的用户使用。
3.1 访问限定符
[访问限定符说明]:
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- 如果后面没有访问限定符,作用域就到}即类结束。
- class的默认访问权限为private, struct为public(因为struct要兼容C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
[面试题]:
问题: C++中struct和class的区别是什么?
解答: C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一 样的,区别是struct定义的类默认访问权限是public, class定义的类默认访问权限是private。 注意:在继承和模板参数列表位置,struct和class也有区别。
3.2 封装
面向对象的三大特征:封装、继承、多态。
封装本质上是一种管理,让用户更方便使用类。
**封装:**将数据和操作数据的方法进行有机结合,通过访问限定符隐藏对象的属性和实现细节,仅使用对外公开的接口来和对象进行交互。
四、类的作用域
**类定义了新的作用域,**类的所有成员都在作用域中。在类外定义成员时,需要用到::作用域操作符指明成员属于哪个类域。
五、类的实例化
用类类型创建对象的过程,称为类的实例化
- 类是对对象进行描述的,相当于一个模型成员变量是声明,限定了类有哪些成员,定义一个类并没有给它分配实际的内存空间来存储它。
2.一个类可以实例化出多个对象,实例化出的对象,占用实际的物理空间,存储了类的成员变量。
3.类只是一个设计,实例化出的对象才能存储数据,占用物理空间。
分析如下:
总结:不同对象,成员函数调用的地址一样(数据不存对象里),成员变量存数据不一样(存在各自的对象里)
六、类的对象大小的计算
1.类对象的存储方式
类中既可以有成员变量,也可以有成员函数。(类里面只存成员变量,不存成员函数)
为什么成员变量在对象中,成员函数不在对象中?
一个类分为成员变量和成员函数,类的大小是由成员变量来决定得。这是因为每个对象的成员变量是不一样得,需要独立存储,而每个对象调用成员函数是一样的,都是放在共享公共区域(代码段)里。
2.类的大小计算
一个类的大小,实际上是该类“成员变量”之和,要注意内存对齐,要注意空类的大小,空类比较特殊,编译器给空类一个字节用来唯一标识这个类的对象(这个1byte不存储有效数据,是用来占位得,占位的意思是标识这个对象被实例化出来了)。
#include <iostream>
using namespace std;
//即有成员变量,又有成员函数
class A1
{
public:
void f1()
{};
private:
int a;
char b;
short c;
};
//只有成员变量
class A2
{
private:
int a;
char b;
short c;
};
//只有成员函数
class A3
{
public:
void f1()
{};
};
//没有成员函数,也没有成员变量
class A4
{
//空
};
int main()
{
cout << sizeof(A1) << endl;
cout << sizeof(A2) << endl;
cout << sizeof(A3) << endl;
cout << sizeof(A4) << endl;
return 0;
}
结构体的内存对齐规则
1.第一个成员在与结构体偏移量为0的地址处。
2.从第二个成员开始,成员变量要对齐到对齐数的整数倍的地址处。
注意:对齐数=编译器默认的一个对齐数与该成员大小的较小值,VS中默认对齐数为8.
3.结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4.嵌套结构体:嵌套的结构体对齐到自己的最大对齐数的整数倍,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
七、类成员函数this指针
this指针可以用来确定不同对象的成员函数,每个成员都有隐形的指针。
7.1 this指针的引用
C++中通过引入this指针解决了不同对象相同类调用成员函数(对象如何找到自己的成员函数)的问题:
C++编译器给每个“非静态的成员函数"增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中对所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
7.2 this 指针的特性
1. this指针的类型:类的类型* const ,即成员函数中,不能给this指针赋值。
2. 只能在"成员函数”的内部使用。
3. this指针本质上是“成员函数”的形参 ,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
4. this指针是“成员函数"第一个隐含的指针形参, 一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
扩展:
#include <iostream>
using namespace std;
class A
{
public://公有
void Print()
{
cout << "Print()" << endl;
}
private://私有
int _a;
};
int main()
{
A* s1=nullptr;
s1->Print();
return 0;
}
#include <iostream>
using namespace std;
class A
{
public://公有
void Print()
{
cout <<this-> _a << endl;
}
private://私有
int _a;
};
int main()
{
A* s1 = nullptr;
s1->Print();
return 0;
}
仔细观察这两段代码,第一个正常运行,第二个运行崩溃。
1.this指针存在哪里?
this指针是个形参,是存在栈帧上面得,是隐含形参。(VS编译环境下,this指针存在函数栈帧中的寄存器里)
2.this指针可以为空吗?
在特定条件下可以为空, 成员函数地址不在对象里,成员变量在对象里,对象为空,只调用成员函数,且不需要用到隐含this指针时,就能正常运行。
补充:
c语言和c++的使用特点:
C语言:结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体中,数据和操作数据的方法是分离开的,实现上相当复杂,涉及大量指针操作,很容易出错。
c++:c++通过类可以将数据以及操作数据的使用方法进行完美结合,通过权限访问可以控制这些方法在类外可以被调用,这就是封装。
c++中Stack* 参数是编译器维护,C语言中需要用户自己维护。
总结:
C语言:1.数据和方法是分离的。 2数据访问控制是自由的,不受限制。
c++:1.数据和方法都封装到类里面。2.控制访问方式。愿意给你访问就是公有,不愿意给你访问就是私有。
C语言和c++的底层都在代码段里,区别就是对数据的管理不同。