1.关于c语言和c++对于struct用法
c语言中struct是用来定义结构体的
struct listnode_C//c语言定义结构体,类型为struct listnode_C { int val; struct listnode_C* prev;//结构体指针 struct listnode_C* next; };
c++中,兼容c的struct定义结构体的用法,但是同时struct也可以用来定义类
struct listnode_CPP//C++定义类,把listnode_CPP看作类名 { // 类型为listnode_CPP int val; listnode_CPP* prev; listnode_CPP* next; listnode_CPP* createnode(int val);//定义成员函数 };
2. c++中使用class和struct定义类的区别?
- 默认访问限定符不同
struct listnode_CPP//使用struct { int val; listnode_CPP* prev; listnode_CPP* next; };
- 使用struct 默认访问限定符为 public (共有的),在类外面可以访问到
class listnode_CPP//使用class { int val; listnode_CPP* prev; listnode_CPP* next; };
- 使用class 默认访问限定符为private(私有的),在类外面不能访问到
3. 类的实例化
用类类型创建对象的过程,称为类的实例化
类也可以看作是设计图,而类的实例化则使用图纸建造房子,需要使用图纸来建造房子
1.成员变量的声明和定义
#include<iostream> using namespace std; class stack { public: void push(int x);//成员函数 private: int a;//成员变量的声明 }; int main() { stack s1;//相当于将成员函数整体定义 return 0; }
- 由于类中的成员变量a没有开辟空间,所以是成员变量的声明
- 对类的对象实例化这个过程中,创建s1对象开辟了空间,由于开辟了空间所以对成员变量整体定义
2.成员函数的定义和声明
1. 在类里面定义
#include<iostream> using namespace std; class stack { public: void push(int x)//成员函数 { //..... } private: int a; }; int main() { stack s1;//类的对象实例化 s1.push(1); return 0; }
- 成员函数直接定义到类里面
2. 在类外面定义
#include<iostream> using namespace std; class stack { public: void pop(int n=4);//成员函数的声明 private: int a; }; //在类外面定义 void stack::pop(int n)//成员函数的定义 { //... } int main() { stack s1; s1.pop(); return 0; }
- stack::pop 说明 pop成员函数是stack类中的
- 由于缺省参数声明和定义不能同时出现,所以只在成员函数的声明缺省
4.类的大小计算
#include<iostream> using namespace std; class stack { public: void push(int x); void pop();//成员函数 void destory(); int a; private: int b;//成员变量 }; int main() { stack s1; cout << sizeof(s1) << endl;//结果为8 return 0; }
因为成员函数有3个,成员变量有2个,故只计算了成员变量的大小
1.只计算成员变量的原因
一个类实例化N个对象,每个对象的成员变量都可以存储不同的值,所以被独立存储
调用的成员函数却是同一个,如果每个对象都放成员函数,而这些成员函数确是一样的,就会浪费空间,为了不浪费空间,就把成员函数放入公共区域——代码段
举例
#include<iostream> using namespace std; class stack { public: void push(int x); void pop()//成员函数 { //.... } void destory(); int a; private: int b;//成员变量 }; int main() { stack s1; s1.a = 5; s1.pop(); stack s2; s2.a = 4; s2.pop(); stack s3; s3.a = 3; s3.pop(); return 0; }
通过stack这个类,实例化出s1 、s2、s3 这三个对象
s1.a=5 s2.a =4 s3.a=3
成员变量a每次被赋予的值都是不同的值
但每次pop这个成员函数的调用是相同的
2. 如何计算一个类的实例化的对象的大小
计算成员变量之和,并且考虑内存对齐规则
没有成员变量的大小为1
举例
#include<iostream> using namespace std; class A1//类中既有成员函数,又有成员变量 { public: void f1() { //... } private: int a; char b; }; class A2//类中仅有成员函数 { public: void f2() { //... } }; class A3//类中什么也没有 { //... }; int main() { cout << sizeof(A1) << endl;//8 cout << sizeof(A2) << endl;//1 cout << sizeof(A3) << endl;//1 return 0; }
A1
VS默认对齐数为8
a为int,字节大小为4 , 4<8 即a的对齐数为 4
b为char,字节大小为1, 1<8 即b的对齐数为1
4为最大对齐数,整体结构需为最大对齐数的整数倍
整体结构为5 , 5>4 , 补齐后为 8
即结果为 8
为什么没有成员变量的大小为1(如A2 A3),而不是0?
- 开一个字节不是为了存数据,而表示对象存在
#include<iostream> using namespace std; class A2//类中仅有成员函数 { public: void f2() { //... } }; int main() { A2 a;//1 A2 b;//1 A2 c;//1 return 0; }
- 当使用A2类实例化多个对象时,若类的大小为0,没有空间存在,则 &a,&b,&c,就会报错,故选取一个字节是为了表示数据存在
5. this指针
1. 隐藏的this指针
- this指针是由编译器自动实现的,不可以我们自己加上
#include<iostream> using namespace std; class date { 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 d; d.init(2022, 12, 11); d.print(); return 0;//2022-12-11 }
明明print中没有参数的存在,为何可以出现结果?
- 实际上是将&d传过去,由编译器实现的this指针接收,通过this指针找到当前对象d中_year,_month,_day,从而求出对象d所对应成员变量的结果
同样的init成员函数也包含隐藏的this指针
- 通过编译器实现的this指针使形参year,month,day赋值给对应的对象的成员变量中
2. this指针存在哪里?
- 当对象调用函数时,将对象的地址作为实参传给this形参,所以对象中不存储this指针,而是在栈上
- VS下面是通过ecx寄存器存储(优化)
3. 例题
#include<iostream> using namespace std; class A { public: void printA() { cout << _a << endl; } void show() { cout << "show()" << endl; } private: int _a; }; int main() { A* p = nullptr; p->_a;//崩溃 p->printA();//崩溃 p->show();//正常运行 return 0; }
- p->_a会引起程序崩溃,因为_a是成员变量,在对象里面,会使指针去所指向对象p中寻找,p是NULL,会造成NULL解引用
因为printA函数和show函数都在公共代码段中,所以p->printA()和p->show()不会去指针所指向的对象中寻找,这里不会崩溃
- p为nullptr,this指针作为p的形参,所以this==NULL,NULL解引用程序就会崩溃
- 虽然this==NULL,但是输出并没有用到this指针,没有访问NULL ,所以程序正常运行
6. 封装
1.数据和方法都封装到类里面
- c++类的成员函数 即方法 ,成员变量即数据
#include<iostream> using namespace std; class date { public: void push(int x);//成员函数 private: int b;//成员变量 }; int main() { return 0; }
2.把想给你看到的数据给你,不想给你看封装起来
访问限定符: public (共有的) protected (保护) private (私有)
a属于public 类中 ,属于想给你看到的数据 ,而 b属于 private 类中,属于不想给你看到的
#include<iostream> using namespace std; class date { public: int a; private: int b; }; int main() { return 0;
public定义的成员变量在类外面可以访问,
private定义的成员变量不可以在类外面访问