类和对象是很重要的知识点,对于初学者也不容易理解。希望大家多学几遍,搞懂内容,在进一步学习下一步的内容,学习c++就得一步一步来,打好基础,稳定向前。
C语言是面向过程的,关注的是过程,分析求出解决问题的步骤,通过函数调用逐步解决问题。
c++是面向对象的,关注的是对象,将一件事情拆分为不同的对象,靠对象之间交互完成。
1.类的引用
1.c++兼容c结构体的用法
2.c++把结构体升级成了类,类名就是类型(可以用class代替)。
3.类是一个整体,有成员变量和成员函数,并且位置任意。
4.struct默认公有,class默认私有。
5.类是一个整体,不需要定义在前面或者后面。
2.类的定义
class为定义类的关键字,Classname为类的名字,{}中为类的主体,注意类定义后面分号不能省略。
类主体的内容称为类的成员:类中的变量叫成员变量,函数称为成员函数。
类的两种定义方法:
1.声明和定义全部在类体中。
#include
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++实现封装的方式: 用类将对象的属性和方法结合在一块,让对象更加完善,通过访问限定符选择性的将接口提供给外部的用户使用。
面向对象的三大特征:封装、继承、多态。
封装本质上是一种管理,让用户更方便使用类。
**封装:**将数据和操作数据的方法进行有机结合,通过访问限定符隐藏对象的属性和实现细节,仅使用对外公开的接口来和对象进行交互。
**类定义了新的作用域,**类的所有成员都在作用域中。在类外定义成员时,需要用到::作用域操作符指明成员属于哪个类域。
用类类型创建对象的过程,称为类的实例化
分析如下:
总结:不同对象,成员函数调用的地址一样(数据不存对象里),成员变量存数据不一样(存在各自的对象里)
1.类对象的存储方式
类中既可以有成员变量,也可以有成员函数。(类里面只存成员变量,不存成员函数)
为什么成员变量在对象中,成员函数不在对象中?
一个类分为成员变量和成员函数,类的大小是由成员变量来决定得。这是因为每个对象的成员变量是不一样得,需要独立存储,而每个对象调用成员函数是一样的,都是放在共享公共区域(代码段)里。
2.类的大小计算
一个类的大小,实际上是该类“成员变量”之和,要注意内存对齐,要注意空类的大小,空类比较特殊,编译器给空类一个字节用来唯一标识这个类的对象(这个1byte不存储有效数据,是用来占位得,占位的意思是标识这个对象被实例化出来了)。
#include
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指针可以用来确定不同对象的成员函数,每个成员都有隐形的指针。
C++中通过引入this指针解决了不同对象相同类调用成员函数(对象如何找到自己的成员函数)的问题:
C++编译器给每个“非静态的成员函数"增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中对所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
1. this指针的类型:类的类型* const ,即成员函数中,不能给this指针赋值。
2. 只能在"成员函数”的内部使用。
3. this指针本质上是“成员函数”的形参 ,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
4. this指针是“成员函数"第一个隐含的指针形参, 一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
扩展:
#include
using namespace std;
class A
{
public://公有
void Print()
{
cout << "Print()" << endl;
}
private://私有
int _a;
};
int main()
{
A* s1=nullptr;
s1->Print();
return 0;
}
#include
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++的底层都在代码段里,区别就是对数据的管理不同。