C++复习01

C++入门01

C++中的关键字(与版本有关)

98版-63个

命名空间:

1.什么是命名空间:一个作用域 一个班级/一个院系/一个学校
2.命名空间的作用:防止命名冲突
3.如何定义一个命名空间:namespace N1{变量、函数}
命名空间中的成员如何使用:
a.N1::成员名字:当前命名空间在内容中使用少
b.using N1::b;
c.using namespace N1;

缺省参数(相当于备胎的存在)

1.概念:如果在定义函数时,在函数的参数带上一个默认值,在使用时可以传参,也可以不传参。如果用户传递的实参,使用用户传递的实参。如果用户没有传参,则使用默认值。

2.分类:半缺省参数和全缺失参数
半缺省参数:部分参数带有默认值,注意:只能从右往左依次给出,匹配从左往右

void TestFunc(int a,int b,int c=1){}
TestFunc(1,2);    a=1,b=2
全缺失参数:所有参数带有默认值
void TestFunc(int a=3,int b=2,int c=1){}
{}

全缺省和不带类型参数不要同时存在

void TestFunc1(){}
void TestFunc1(int a=1){}  
TestFunc1();//编译失败,调用时编译器不知道应该调用哪一个

3.注意事项:
a.默认参数设置规则:从右往左依次给出
b.不能在声明和定义时同时给出 两位置默认参数给的不一致的话,编译器不知道用哪个
类似于男女朋友关系:1对1 1对多则不行
c.默认参数提供方式:常量、全局变量
d.C语言不支持

函数重载!!!!

1.概念:在同一个作用域,如果存在多个相同名称的函数,并且参数列表不同 与返回值类型是否相同无关(参数个数、参数类型、类型次序) 一词多义
对于与返回值类型是否相同无关进行解释:

int Add(int,int)
double Add(int,double)
Add(1,2);
此时编译器不知道该调用哪一个

举一个例子,后面解释均使用该例子:

int Add(int a,int b);
double Add(double a,double b);

2.调用原理:

可成功编译:
Add(1,2);
Add(1.0,2.0);

编译阶段,编译器会推演函数实参的类型,根据推演的结果选择合适的函数进行调用,如果没有合适的函数或有多个函数可以选择,编译器会报错

编译失败:
Add(1,2,3);//int int int 没有三个int类型的定义 编译报错
Add(1.0,2.0);//int double 尝试进行类型转化,转化分为两种情况: a.int int  b.double double
此时编译器不知道到底应该选择哪一个而引起二义性

3.C++为什么可以支持函数重载,而C语言不可以
关键:C++与C语言关于名字修饰的规则,名称修饰规则不同
C语言名字规则:编译器只是在函数名字前添加_
例如: _Add _Add
C++名字修饰规则:函数名字_参数类型1_参数类型2_参数类型编译到函数类型中
windows:?@Add@HHHYA
(方法:只给声明,不给定义。调用、链接期间会报错,在报错信息中查看)
linux:Z3Addii(3:名字中3个字母 ii:两个参数)

扫描二维码关注公众号,回复: 9064128 查看本文章

4.exern "C"的作用:
将函数按照C语言的方式进行编译

引用:

1.概念:引用是一个别名,与其引用的实体公用同一块内存空间,编译器不会给引用变量重新开辟一块新的内存空间
相当于把猫叫咪 或是自己的小名

2.特性:

  • 引用定义时必须初始化
  • 一个实体可以有多个引用
  • 一个引用一生只能与一个实体进行结合:引用一旦引用了一个实体,就不能再去引用其他实体

3.常引用:const类型的引用

const int a=10; int &ra=a; //报错   
改为const int &ra=a;
const int &b=10;
double d=12.34; int &rd=d;//报错 引用变量与实体类型不一样 
改为const  int &rd=d;

变量类型之间的转换需要借用临时变量。
const在C++中代表常量,不光能修饰普通变量,也能修饰指针,还能针对函数的参数、返回值以及类的成员函数进行修饰。
临时变量:用户既不知道临时变量的名字,也不知道该块空间的地址,就无法修改该空间中的内容,认为临时变量具有常性–将去看成一个常量,返回值都具有常性。

4.作用-参数、返回值:
C++在共有三种传参方式:
a.传值
b.传地址
c.传引用

  • 传参效率比较高(在传参期间就不会生产实参的一份拷贝)也比较节省空间,因为不会再生成一份实参
  • 可以通过修改形参来改变实参(形参是实参的一个别名)

一般在C++中,传参时能用引用尽量用引用,如果不需要用形参改变实参,可以用const来进行修饰
引用作为函数返回值:不能返回函数栈上的空间,因为如果函数返回后,离开函数作用域后,其栈上空间已经还给系统,因此不能用栈上的空间作为引用类型返回。

5.传引用、传值效率:
传参效率:传引用比传值效率高
传引用和传指针:效果基本相同

6.引用和指针的区别:!!!!!

a.从概念:引用–别名,与其引用的实体共用同一块内存空间
b.从底层实现:编译器在底层实际是将引用转换为指针类进行处理
因此引用在底层实际也有自己的内存空间
换一种角度来说,引用和指针在底层实现上是没有区别
c.引用和指针的不同点:

  • 引用在定义时必须初始化,指针没有要求
  • 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型
    实体
  • 没有NULL引用,但有NULL指针
  • 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占
    4个字节)
  • 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
    -有多级指针,但是没有多级引用
    -访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  • 引用比指针使用起来相对更安全

内联函数和宏函数的区别:!!!!!

C语言中的宏:宏常量和宏函数
宏常量:
优点:能够提高代码的可读性,一改全改
int a[100]
缺陷:宏常量没有类型,在编译阶段就不会进行类型检测
#define PI 3.14
C++中为了解决宏常量的缺陷:在C++中使用const修改某个实体,该实体不仅仅是一个常量,而且在编译阶段也可以进行替换
宏函数:在C语言中,为了提高代码的运行效率,会将一些比较短小的代码利用宏函数来代替
在预处理阶段会用宏体来替换宏函数
优点:
可以提高代码的运行效率,宏函数参数尽可能用括号括起来
缺点:
1.对于宏函数的参数没有加括号时,可能会造成错误
2.因为宏函数在预处理阶段已经被替换,因此不能进行调试
3.宏函数的参数没有类型,也不会进行参数类型检测,错误会延迟到运行时,增加错误的代价
4.副作用,没有安全性检查

内联函数–解决宏函数缺陷
1.概念:在C++中用inline修饰的函数,编译器会将其作为内联函数来进行处理
2.作用:编译器在编译阶段,会用内联函数替换函数的调用,少了函数调用的开销,提高代码的运行效率
注意:inline是一个建议性的关键,建议编译器将函数当成内联函数来处理,但实际不一定。函数中最好不要有循环、递归,函数不易太长。
如果一个函数在类中进行定义,编译器也会将该函数当成内联函数来处理
优点:
1.参数不需要导出加括号
2.内联函数是一个函数,会参与编译,在编译阶段会进行参数类型检测
3.在debug版本下可以进行调试
4.没有副作用
缺陷:可能会引起代码膨胀
补充:在C++中,哪些函数不能作为内联函数:构造函数、析构函数、static修饰成员函数、虚函数

C++三大特性:封装、继承、多态

类和对象–封装特性

1.什么是面向对象,面向对象和面向过程区别:
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
2.类的定义:将类的定义和声明全部放在类中,将类的声明和定义分开,头文件中放声明,源文件中放定义–>如果成员函数在类外进行定义,必须在函数名字前增加类名::
3.访问权限:public、protected、private

  • public修饰的成员在类外可以直接被访问
  • protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
  • 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
  • class的默认访问权限为private,struct为public
    4.什么是封装?C++中是如何进行封装?
    封装概念:将一个事物的内部实现细节包装起来,只需要对外提供操作对象的接口
    C++如何实现封装:通过类的方式对对象进行封装,通过访问权限控制哪些接口可以提供给外部来进行使用
    比如说我们常用的手机。手机内部组织结构用户不需要知道,都是通过接口暴露给用户
    5.一个类就是一个作用域
    6.类的实例化:用类类型创建对象的过程
    类和对象密不可分
    类:类是用来描述一个对象的,对象都有哪些属性,对象都有哪些方法 相当于建房子的图纸
    对象:用类创建出来的一个实体 相当于房子
    7.如何求一个类的大小
    a.通过编译器来猜测:首先找出对象 接下来列出对象所对应类的所有成员
    对象中既包含成员变量,也包含成员函数
    b.对结论1进行分析–如果每个对象中都包含成员函数,比较浪费空间
    将成员变量和成员函数分开存放,对象中只存放成员变量+指针(指向所有成员函数存放位置的起始地址)
    c.对a和b进行验证:
    最终结论:对象中只包含类中的非静态的成员变量
    只需要将对象中成员变量加起来,注意内存对齐
常见面试题:空类大小的计算方式?

主流编译器中:空类大小为1,为什么不是0,原因?
A abc
如果空类大小为0,abc所占位置相同,此时abc会被看成一个对象,而现实中,abc为三个不同对象。编译器无法区分abc三个对象

常考内容:

1.什么是结构体内存对齐?结构体为什么要内存对齐?
平台原因(移植原因):在计算机在内存读取数据时,只能在规定的地址处读数据,而不是内存中任意地址都是可以读取的。
效率原因: 正是由于只能在特定的地址处读取数据,所以在访问一些数据时,对于访问未对齐的内存,处理器需要进行两次访问;而对于对齐的内存,只需要访问一次就可以。 其实这是一种以空间换时间的做法。
2.结构是如何进行内存对齐?
第一个成员在与结构体偏移量为0的地址处。
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS中默认的对齐数为8
结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
3.如何让编译器按照指定的字节数来进行对齐?是不是结构体可以按照任意的字节数来进行对齐?
指定对齐值:#pragma pack (value)时的指定对齐值value
方式一:可以通过预处理指令
方式二:可以通过编译器进行处理
在windows中,VS编译器下,默认对齐数为8; 在Linux中,默认对齐数为4
对齐参数不能任意设置,只能是内置类型已有的字节数,如:char(1)、short(2),int(4),double(8)…不能是3,5…任意数。
4.如何知道结构体中某个成员相对于结构体起始位置的偏移量?
a、从零偏移处开始,按字节大小计算,判断此偏移地址是否为该成员变量和对齐参数两者之间的最小值,即min(对齐参数,sizeof()成员);
b、若是,则从此处开始占用内存,大小为该类型所占字节数值,若不是,则内存向后偏移到最小值整数倍处,再开始占用空间。
c、按a、b、两步骤算出结构体实际所占内存时,为了方便后面类型的存储,再向后偏移一位,然后判断该地址是否是默认对齐数与该结构体中最大类型所占字节数的最小值 ,即:min(默认对齐参数,类型最大字节数)的整数倍,若是,则当前偏移地址的字节数便是结构体大小,若不是,继续向后偏移,直至为最小值整数倍为止。

例子:
struct   A
      {
       int a;
       char b;
       double c;
       char d;
      };

int占4个字节。char占1个字节。float占4个字节。double占8个字节。
在这里插入图片描述
5.什么是大小端?如何测试一个机器是大端还是小端?能否给出一个大小端的应用场景?
大端:高字节放在低地址。
小端:低字节放在低地址。
unsigned int value = 0x19345768,用unsigned char buf[4]来表示value
  ---------------
  buf[3] (0x68) – 低位
  buf[2] (0x57)
  buf[1] (0x34)
  buf[0] (0x19) – 高位
  ---------------
  ---------------
  buf[3] (0x19) – 高位
  buf[2] (0x34)
  buf[1] (0x57)
  buf[0] (0x68) – 低位
  --------------
定义一个int变量,将其地址强制为char *地址,检测该地址中的数据。若是int变量的最低字节,则是小端机,反之则为大端机。

#include<stdio.h>
int check_sys()
{
    int i = 1;     
    return (*(char*)&i);
}
int main()
{
    int ret = check_sys();
    if (ret == 1)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}

在网络上传输数据时,由于数据传输的两端对应不同的硬件平台,采用的存储字节顺序可能不一致。所以在TCP/IP协议规定了在网络上必须采用网络字节顺序,也就是大端模式。
对于char型数据只占一个字节,无所谓大端和小端。
而对于非char类型数据,必须在数据发送到网络上之前将其转换成大端模式。
接收网络数据时按符合接受主机的环境接收。

发布了37 篇原创文章 · 获赞 3 · 访问量 1055

猜你喜欢

转载自blog.csdn.net/weixin_43264873/article/details/104250780
今日推荐