C++兼容C语言,是C语言的升级版。
我们首先来探讨一下C++与C语言中,结构体的异同。
1.C语言中结构体内只能定义变量,而C++中结构体内不仅能定义变量还能定义函数。
2.C语言定义结构体类型变量,struct struct_name 变量名,而C++中定义结构体类型变量,struct_name 变量名。
/*1.C语言和C++中结构体struct的区别*/
#include
using namespace std;
//C语言
struct node {
int data;
struct node* next;
};
//C++
struct struct1 {
int data;
void ShowData() {
cout << data << endl;
}
};
int main() {
struct node st1;
st1.data = 10;
cout << st1.data << endl;
struct struct1 st2;
st2.data = 20;
st2.ShowData();
node st3;
st3.data = 10;
cout << st3.data << endl;
struct1 st4;
st4.data = 20;
st4.ShowData();
return 0;
}
C语言关注面向过程的,关注的是过程,而C++是基于面向对象的,关注的是对象。
面向对象的三大特性:封装、继承、多态。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
例如,当我们使用洗衣机时,我们不需要在乎洗衣机内部是怎么运作的,我们只需要把衣服放进洗衣机内,然后加入洗衣液,按下洗衣机上面的按钮对洗衣机进行操作。洗衣机就是一个被封装起来的家具,我们只需要知道洗衣机上面的按键是用来做什么的,有什么用,如何使用即可,洗衣机到底是怎么运作的,里面的线路是什么样的,都是不可见的,我们也不需要知道。
因此我们发现,封装的意思是把一些东西装进一个容器,有些东西对外可见,有些东西对外不可见,组成起来的整体为我们服务。
但是我们发现,C语言和C++中,如果我们想要使用struct自定义类型,那么内部的成员,对外都是可见的。struct确实是可以把一些东西框起来,框起来的所有东西,对外都是可见的,为了满足有些东西对外可见,有些东西对外不可见,我们引入了访问限定符。
public修饰的成员在类外可以直接被访问。
private修饰的成员在类外面不可直接被访问。
protected和private类似,具体什么区别后面再详细讲解。
#include
using namespace std;
struct struct1 {
public:
void InitData(int data) {
_data = data;
}
void ShowData() {
cout << _data << endl;
}
private:
int _data;
};
int main() {
struct1 st;
st.InitData(100);
st.ShowData();
return 0;
}
有了public和private访问限定符,我们就可以对框起来的东西进行控制,哪些我想要对外界可见,哪些不想对外界可见,只需要添加public和private即可。
访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止如果后面没有访问限定符,作用域就到 } 即类结束。
我们在介绍C++和struct结构体异同中,struct里面的成员默认是对外界可见的,也就是默认的访问限定符是public。而C++引入了一个class定义类,该类里面的成员默认对外界不可见,也就是默认的访问限定符是private。class类和struct的区别仅仅是默认访问限定符的不同。封装特性用struct封装似乎与struct原本的意义不同,因此引入一个新的关键词class特定表示封装类。
/*2.C++中类的定义*/
#include
using namespace std;
struct struct1 {
void ShowData() {
cout << data << endl;
}
void InitData(int _data) {
data = _data;
}
int data;
};
class class1 {
void ShowData() {
cout << data << endl;
}
void InitData(int _data) {
data = _data;
}
int data;
};
class class2 {
public:
void ShowData() {
cout << data << endl;
}
void InitData(int _data) {
data = _data;
}
private:
int data;
};
int main() {
struct1 st1;
st1.InitData(10);
st1.ShowData();
class1 cl1;
cl1.InitData(20);
cl1.ShowData();
class2 cl2;
cl2.InitData(30);
cl2.ShowData();
return 0;
}
class1类中,我们没有添加public或者private访问限定符修饰,默认的访问限定符是private,在类外面不可直接被访问。因此
class1 cl1;
cl1.InitData(20);
cl1.ShowData();
这段代码可以定义类,但是不可以调用里面的成员函数。
如果我们注释掉这段代码,运行得到的结果如下:
我们发现可以直接访问struct1结构体内的函数,class2中被public修饰的成员函数也可以被外界访问,但是没有被public修饰的class1中,不可被外界访问。
因为struct结构体内默认的访问限定符是public,而class类内默认访问限定符是private。
/*3.类的作用域*/
#include
using namespace std;
class Person {
public:
void ShowPersonInfo();
void InitPersonInfo();
private:
char _name[20];
char _gender[3];
int _age;
};
void Person:: ShowPersonInfo() {
cout << _name << " " << _gender << " " << _age << endl;
}
void Person::InitPersonInfo() {
cin >> _name >> _gender >> _age;
}
int main() {
Person p1;
p1.InitPersonInfo();
p1.ShowPersonInfo();
return 0;
}
类和结构体一样可以理解为自定义类型。自定义数据类型。类内的函数不仅可以在类内被实现,还可以在类外面被实现,在类外面被实现时,需要指定这个函数是在哪一个类里面的。在函数名前面添加“类名+::”。
类定义了一个新的作用域,类的所有成员都在类的作用域中。
用类数据类型定义对象的过程,称为类的实例化。
通俗的说就是用我们自定义类型创建变量的过程,而我们称这个变量叫做对象,这个过程叫做类的实例化。
类就像是一个房子的图纸,你可以用这个图纸创建许多的房子。也就是定义许多个该数据类型的变量。
/*4.类的对象模型*/
#include
using namespace std;
class A1 {
public:
void ShowA() {
cout << _a << endl;
}
private:
int _a;
char _ch;
};
class A2 {
public:
void ShowA() {}
};
class A3 {
private:
int _a;
char _ch;
};
int main() {
cout << sizeof(A1) << endl << sizeof(A2) << endl << sizeof(A3) << endl;
}
我们思考一个问题,类内的内存大小是如何计算的,也就是上述三个类他们的内存大小分别是多少?
我们可以先分析一下这个简单的类的内大小是多少。
#include
using namespace std;
class A1 {
int _a;
char _ch;
};
int main() {
cout << sizeof(A1) << endl;
}
答案是8,int的内存大小是4字节,char的内存大小是1字节,正常来说总内存应该是1+4=5才对。导致计算出来的内存是8的原因是内存对齐。
内存对齐的规则:
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的对齐数为8
结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
int内存占4字节,char内存占1字节,所有数据类型字节最大的是int,4字节,4字节再与默认对齐参数比较取小的一个,得到最大对齐数是4,因此内存一定是4的整数倍。
因此答案是8字节。
接下来我们可以重新思考一下上述问题。
/*4.类的对象模型*/
#include
using namespace std;
class A1 {
public:
void ShowA() {
cout << _a << endl;
}
private:
int _a;
char _ch;
};
class A2 {
public:
void ShowA() {}
};
class A3 {
private:
int _a;
char _ch;
};
int main() {
cout << sizeof(A1) << endl << sizeof(A2) << endl << sizeof(A3) << endl;
}
A1和A3比较,我们发现A1中函数的内存没有保存在A1中。实际上类对象中只保存成员变量内存,而类的成员函数保存在公共代码区。
一个只有函数的类,内存是1不是0,因为你定义了该类对应的对象,你占用内存是0,那和没定义有什么区别,为了表示这个对象确确实实存在,用内存为1的大小表示该内存在,可以理解为占位。
/*5.this指针*/
#include
using namespace std;
//C++
class Date {
public:
void Init(int year, int month, int day) {
_year = year;
_month = month;
_day = day;
}
void ShowInfo() {
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
//C语言
struct Date1 {
int _year;
int _month;
int _day;
};
void InitDate1(struct Date1* d, int year, int month, int day) {
d->_year = year;
d->_month = month;
d->_day = day;
}
void ShowDate1Info(struct Date1* d) {
printf("%d-%d-%d", d->_year, d->_month, d->_day);
}
void testC() {
Date1 dt;
InitDate1(&dt, 2024, 1, 28);
ShowDate1Info(&dt);
}
int main() {
cout << "C++:" << endl;
Date t1, t2;
t1.Init(2024, 1, 26);
t2.Init(2024, 1, 27);
t1.ShowInfo();
t2.ShowInfo();
cout << "C语言" << endl;
testC();
}
对比上述日期类在C语言和C++中的实现,我们发现C语言中必须传日期类数据类型变量的地址,根据地址进行初始化和访问。但是在C++中我们直接t1.Init();就可以对t1内成员进行修改数据并访问。按理来说我们应该知道t1的地址才可以对t1地址上的数据进行修改和访问。
实际上C++中类中的函数隐藏了this指针。
编译器默默地帮我们把地址传过去了,这样我们使用的时候就不需要再传地址。
this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递
最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。
同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。
谢谢您的支持,期待与您在下一篇文章中再次相遇!