C++的函数生成规则和什么有关系?
函数原型 :返回值+函数名+形参
形参 :形参的个数 形参的顺序 形参的类型
c.cpp的相互调用
C++ extern "C" 包含代码是以c规则处理
1.C++ 可以直接调用C
2.C调用C++
1.C++文件可以修改 C++
2.C++文件不可修改 加中间层 .cpp
3.不确定编译
#ifdef __cplusplus
C/C++的区别
1. C: 面向过程的语言 (只能写面向过程的代码)
C++: 面向对象的语言 (既可以写面向过程的代码,也可以写面向对象的代码)
因此C++语言有 类和对象、继承多态这样的OOP语言必备的内容,设计模式:单例模式,工厂、观察者模式;
此外C++支持 模板、运算符重载、异常处理机制、以及一个非常强大的C++标准模板库STL;
另外一个Boost库现在也归C++标准库,提供很多强大的功能;
2. C++ 支持 带有默认值的函数、函数的重载、inline 内联函数;
3. 动态存储管理不同:malloc/free, new/delete;
4. 关键字 const 、struct 的区别;
5. 管理堆内存的方式的区别(new/malloc , delete/free)(程序运行时内存分布式一样);
6. C++ 多了一个类,就多了一个类作用域;
C++支持namepace名字空间:可以让用户自己定义新的名字空间作用域,避免全局的名字冲突;
7. C++不仅支持指针,还支持更安全的引用,不过汇编代码上,指针和引用的操作是一样的,
由于C++是面向对象的语言,支持类对象、类和类之间的代理、组合、继承、多态等面向对象的设计,
有很多设计模式可以直接使用,因此在设计大型软件的时候,通常都会采用面向对象语言,(而不是面向过程)
可以更好的进行模块化设计,做到软件设计的准则:高内聚、低耦合;
8. 强制类型转换区别:
C 强制类型转换使用() 括号里面加类型进行类型强转;
C++ 有四种自己的类型强转方式:
const_cast :修饰的变量优化到寄存器中,再次访问从寄存器中读取;
const_cast<T*>(a):常用于除去这里a变量或者表达式的const属性,a的类型就是T*;
static_cat :静态转换,更安全的类型转换,它能在内置的数据类型间互相转换,
对于类只能在有联系的指针类型间进行转换;
reinterpret_cast :不相关类型的转换,类似C的强转,
任何指针都可以转换成其他类型的指针,不安全;
dynamic_cast :动态转换:只能用于含有虚函数的类,
支持RTTI类型转换,通常在基类和派生类之间转换时使用;
表达式dynamic_cast<T*>(a)将a值转换为类型为T的对象指针,
如果类型T不是a的某个基类型(a变量的类型或者是a类型的派生类类型),
该操作将返回一个空指针,否则转换成功;
常用于运行时检测a指针指向的对象是否是特定派生类类型的对象;
9. 输入输出方式区别:
C:printf/scanf : C的库函数;
C++:cout/cin :ostream 和 istream 类型的对象;
1.函数默认值;
2.inline内联函数;
3.函数重载;
4.const;
5.引用;
6.malloc,free && new,delete;(动态存储管理)
7.作用域;
1、函数的默认值
C89标准的C语言不支持函数默认值;
C++支持函数默认值,且需要遵循从右向左赋初始值;
1.自右向左依次赋予
2.不能重复赋值
3.一般赋在声明上
2、函数重载
C语言不存在函数重载,
C++根据函数名参数个数参数类型判断重载,属于静多态,必须同一作用域下才叫重载。
函数重载的三要素: 1.同名 2.参数不同 3.同作用域
3、inline函数
C89标准的C语言没有,
C++:在调用点直接展开,不生成符号,没有栈帧的开辟回退,仅在Release版本下生效。一般写在头文件中。
1. inline函数和普通函数的区别:
inline 函数:在编译阶段,在函数的调用点将函数的代码展开,忽略了函数栈帧开辟回退的调用开销,运行效率高;
普通函数:调用在汇编上有标准的 push 压实参指令,然后 call 指令调用函数,给函数开辟栈帧,
函数运行完成,有函数退出栈帧的过程;
3. inline函数和static修饰的函数的区别:
都是本文件可见
static修饰的函数 有开栈 清栈的开销
inline函数 没有开栈 清栈的开销
3.inline和宏的区别:
1. inline 编译阶段处理,有完整的语句类型检查,比宏更安全;
宏 预编译阶段处理,纯粹的字符替换 ,没有任何类型的安全检查,十分的不安全;
2. inline函数在debug版本下和普通函数一样,出了问题很方便进行断点调试,定位问题;
宏 无法调试;
3. inline 函数和普通函数一样,结构模块化清晰,方便阅读;
宏 大量的宏不方便去阅读源码;
4. inline 在函数调用点,把函数的代码直接展开,省去了函数的开销,代码运行效率高;
宏 用宏代替函数定义,替换后还是一个正常的函数调用,有函数调用开销(栈帧开辟和回退);
4.inline函数注意事项:
1.写在.h文件中
2.release版本生效
3.是一个建议,递归、循环都不会出现inline
4.基于实现,不是基于声明
5.inline函数缺点:
inline函数以代码膨胀为代价 以空间换时间
1.当 开栈的开销 > 执行的开销 时 使用
2.当 开栈的开销 < 执行的开销 时 不用
4、引用 &
引用底层就是指针,使用时会直接解引用,可以配合const对一个立即数进行引用。
引用:起别名 但不是指针
少了形参对象的生成 少了构造与析构
1.引用一定要初始化
2.引用不能引用 不取地址的数据
3.引用不能改变
4.引用变量只能使用 引用变量 所引用的数值
不能返回局部变量的地址
不能返回局部变量的地址或引用
常引用 引用不能区地址的数据
不能取地址的数据生成临时量
常引用引用临时量
杜绝间接访问修改常量的风险
5、const
C: 编译阶段 只读变量 常变量有没有做左值 其他处理变量相同
C++: 编译阶段 是真正的常量,但也有可能退化成c语言的常量,默认生成local符号。
1.一定要初始化
2.不能做左值
3.不能间接访问来修改
4.修饰的全局变量 globe ==> local
常对象:const修饰的对象;
常对象只能调用常方法;
常对象不能调用普通方法;
常方法:const修饰this指针:普通对象 和 常对象都可以调用;
普通方法能调用常方法;
常方法来调用普通方法;
const修饰的变量 常量
编译阶段 用到常量的地址会替换成常量初始化的值
常引用: 如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。
常引用声明方式:const 类型标识符 &引用名=目标变量名;
1.在C++中 const 是用来定义常量的,不能作为左值被修改,且必须初始化;
2. const 常量的初始值如果是一个明确的值,那么常量在编译期间会被常量的初始值替换,
(const 常量在编译期间替换规则);
3.在C++中 const 修饰的量也可以是常变量(和C语言相同),此时它只是不能作为左值,
其他性质和普通变量一样,不能定义数组大小,没有编译时期值替换规则等;
4.const 可以修饰成员方法,成为常成员方法,在常成员方法中只能访问其他成员,不能修改其他成员;
普通对象和常对象都可以调用常方法,但是常对象只能调用常方法;
5. const 还可以修饰成员变量,使之成为常成员变量,
因此它的初始化必须写在构造函数的初始化列表当中,否则编译就要报错;
6、malloc free && new delete
new
1.开辟内存并初始化
2.调用构造函数 内存不足 抛出异常
delete
1.调用析构函数
2.释放内存
new/malloc 的区别
1.new 是关键字 malloc 是函数
2.new 自由存储区域 malloc 存储在堆上
3.new可以做初始化 malloc 单纯开辟内存
4、new 不用计算开辟内存的大小;malloc需要指出内存大小;
5、new返回值不需要强转,安全;malloc开辟内存需要传入字节数,返回值void*,需要强转,半开半闭,不安全;
6、new开辟内存失败会抛出异常,需要捕获异常才能判断内存开辟成功或失败;malloc开辟内存失败返回值为NULL;
7、new (set_new_hander)new的底层调用是malloc来开辟内存的 ;
8、new有多个函数 malloc只有一个函数
如 operator new
constructor
9、new可以重载 malloc不能重载
10、new可以开辟const内存 malloc 不能开辟const内存
11、new 可以调用 malloc malloc不能调用new
delete/free的区别:
delete 和 free 都不能重复释放内存;都可以释放空指针;
无论是delete还是free之后都要把指针置空,否则会造成野指针。
delete(删除):释放程序动态申请的内存空间;
delete:会调用析构函数、可以被重载;
delete 后面通常是一个指针或者数组 [],并且只能 delete 通过 new 关键字申请的指针,否则会发生段错误;
delete和delete[]的区别:
delete和delete[]都能释放指针所指向的内存区域。
但delete只会调用一次析构函数,
而delete[]还会调用后续所有对象的析构函数。
当数据类型为基本数据类型时,用delete和delete[]都可以,因为基本数据类型没有析构函数。
free : 释放指针指向的存储空间;
free:不会调用析构函数、不可以被重载;
被释放的空间通常被送入可用存储区池,以后可在调用 malloc、realloc以及 calloc 函数来再分配。
有了malloc/free为什么还要new/delete?
对于非内置数据类型的对象而言,光用maloc/free 无法满足动态对象的要求。
对象在创建的同时要自动执行构造函数, 对象消亡之前要自动执行析构函数。
由于malloc/free 是库函数而不是运算符,不在编译器控制权限之内,
不能够把执行构造函数和析构函数的任务强加malloc/free;
因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,
以及一个能完成清理与释放内存工作的运算符delete;
既然new/delete的功能完全覆盖了malloc/free,为什么C++不把malloc/free淘汰出局呢?
因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存;
如果用free释放“new创建的动态对象”,那么该对象因无法执行析构函数而可能导致程序出错;
如果用delete释放“malloc申请的动态内存”,虽然理论上程序不会出错,但是该程序的可读性很差。
所以new/delete必须配对使用,malloc/free也一样。
7、namespace 名字空间作用域
C++:class
C: 全局作用域 局部作用域
同名的名字空间作用域会合并
用户自己定义新的的名字空间作用域,避免全局变量的名字冲突问题;
namespace
using namespace using指示符 把名字空间作用域下的所有符号暴露在当前作用域
using std::count using声明 声明的符号暴露在using声明当前的作用域
const的用法,C++是怎么处理的
1.在C++中 const 是用来定义常量的,不能作为左值被修改,且必须初始化;
2. const 常量的初始值如果是一个明确的值,那么常量在编译期间会被常量的初始值替换,
(const 常量在编译期间替换规则);
3.在C++中 const 修饰的量也可以是常变量(和C语言相同),此时它只是不能作为左值,
其他性质和普通变量一样,不能定义数组大小,没有编译时期值替换规则等;
4.const 可以修饰成员方法,成为常成员方法,在常成员方法中只能访问其他成员,不能修改其他成员;
普通对象和常对象都可以调用常方法,但是常对象只能调用常方法;
5. const 还可以修饰成员变量,使之成为常成员变量,
因此它的初始化必须写在构造函数的初始化列表当中,否则编译就要报错;
( const & 做形参:1、避免实参被修改,2、接收不能取地址的数据)
(const :1、防止实参被修改,2、接收隐式生成的临时量)
补充:
const修饰指针变量时:
(1)只有一个const,如果const位于*左侧,表示指针所指数据是常量,不能通过解引用修改该数据;
指针本身是变量,可以指向其他的内存单元;
常量指针,意思是在这个指针眼里,它所指向的量是不可改变的常量。
(2)只有一个const,如果const位于*右侧,表示指针本身是常量,不能指向其他内存地址;
指针所指的数据可以通过解引用修改。
指针常量本身不能改变,但是可以改变其所指向的变量。
(3)两个const,*左右各一个,表示指针和指针所指数据都不能修改。
const修饰函数参数,传递过来的参数在函数内不可以改变,与上面修饰变量时的性质一样。
const修饰成员函数:
(1)const修饰的成员函数不能修改任何的成员变量(mutable修饰的变量除外)
(2)const成员函数不能调用非const成员函数,因为非const成员函数可以会修改成员变量
const修饰函数返回值
(1)指针传递,如果返回const data,non-const pointer,返回值也必须赋给const data,non-const pointer。
因为指针指向的数据是常量不能修改。
(2)值传递
如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,
加const 修饰没有任何价值。所以,对于值传递来说,加const没有太多意义。
在编程中要尽可能多的使用const,这样可以获得编译器的帮助,以便写出健壮性的代码。
C++值传递的方式有几种
三种 值传递 指针传递 引用传递
地址传递:地址传递要求实参是变量的地址,实参用取地址符号&取出变量的地址,传递给形参指针*P,
然后在函数里用取值运算符*取出指针p的值进行处理。利用指针从而达到实参与形参的双向传递。
引用传递:引用传递就是给实参中的变量起一个别名。引用传递没有自己的单独的内存空间,作为别名,
它和实参变量共用一段内存空间,形参用&别名。从而给实参变量起了一个别名,
对别名变量进行处理的结果也会影响到实参。从而达到实参与形参的双向传递。
值传递:单向传递, 实参与形参是两个变量,占用了两个不同的内存空间。所以他们传递是单向的,
即实参只能把值传给形参。形参修改后不会影响到实参。程序中只能通过return返回一个值。
要实现一次返回多个值只能是在形参中多定义几个引用传递或者地址传递。
static 关键字
1、扩展生存周期:
1.普通局部变量:属于指令,存放在.text代码段上,运行时在栈上分配空间;
2.static 修饰局部变量:成为数据,放在.data/.bss段,程序一运行就有内存,第一次运行时初始化,
整个进程结束才释放内存;
3.static 修饰普通成员变量,使普通成员变量从栈内存变成在 .data/.bss 存储,生存周期变长了;
2、限制作用域:
1.static 修饰全局变量:使得全局变量从global符号变为local符号,只能当前文件可见,
不参与链接符号解析过程,因此多个源文件可以定义同名的static 全局变量,不会产生重复;
2. Static 修饰普通函数,也是变成local符号,其他文件不能链接这个文件的static函数;
3、static修饰成员方法和成员变量:变成静态成员方法、静态成员变量
1.静态成员方法:形参不会再生成this指针,_cdecl 调用约定,调用时不再依赖对象,
不能访问普通的成员,能访问静态的成员变量,可以用类的作用域来调用;
静态的成员方法 不能 调用普通的成员方法;
普通的成员方法能 调 用静态的成员方法;
2.静态成员变量:必须在类外初始化,同类型所有对象共享静态成员变量,
成员变量就不在依赖对象,而是属于类的,
访问不依赖对象,通过类作用域就能访问,相当于类作用域下的全局变量;
指针与引用的区别
1、 汇编上:指针与引用
汇编上:引用就是指针操作,定义一个引用变量,相当于就是定义了一个指针,
然后把引用内存的地址写到这个指针里面;当通过引用变量修改它所引用的内存时,
先访问指针里面的地址,然后在这个地址的内存里面改值;
2、 指针可以不初始化,通过赋值可以指向任意同类型的内存;引用必须初始化,
且引用一旦引用一块内存,再不能引用其他内存了;
3、 求字节大小时(sizeof),指针在32位系统中永远是4个字节,在64位系统中永远为8字节;
而引用计算的是他所引用内存的大小;
引用,是用作对象的别名。其定义形式为:
T&reference_name =target; T为数据类型,target为T类数据
引用在一定程度上可以取代指针,主要用作函数的形参。
引用必须在初始化的时候确定被引用的的对象,一旦确定引用对象则不可更改。这一点和指针常量类似。
不过存在例外,当引用作为类的成员变量和函数形参定义时,不必进行初始化。
同时引用初始化的对象必须为可以被赋值的左值。在函数形参通过指针传递时,
可以使用引用来实现同样的功能,并且引用的指向不会发生变化,因此更加安全。
class 类和 struct 结构体的区别
1、 Class 能用来定义模板类型参数,就像“typename”;struct 不能;
2、 在C++类型定义时,如果没有给出访问限定符,class默认为private , struct 默认为public;
3、 struct 变量或对象可以以{}的方式给初始值;class 是不行的;
4、 C语言的struct 空结构体,sizeof值为0,
C++中空struct 和 空class,sizeof值为1;
因为C++中类定义的都是对象,需要调用构造函数,构造就需要有内存,构造函数有一个形参this指针,
需要你传一个内存地址,编译器给出最小寻址单位1个字节;C语言的结构体定义的是变量,
只需要分配内存,没有构造,因此空struct 就是0字节;
5、 struct 在C语言中是定义结构,在C++ 中定义的都是类,
因此C++中struct可以包含方法,能写访问限定符,能实现继承多态;默认继承,
基类使用struct 或 class 定义,继承方式一个是public,一个是private;
typename关键字的用法
1、在模板类型参数列表中定义模板类型参数,和class没什么区别;
2、声明类中的的一个类型
typename 和 class的区别
1、都可以在模板类型参数列表中定义模板类型参数,只是为了区别class即定义类又定义模板;
2、class不能声明类中的的一个类型
本文深入探讨C++的各种特性,包括函数生成规则、函数重载、内联函数、内存管理、名称空间、强制类型转换等内容。重点讲解了C++与C语言的区别,以及C++特有的面向对象编程特点。
1万+

被折叠的 条评论
为什么被折叠?



