函数重载
-
同一个作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数称为重载函数
-
返回类型可以相同也可以不同,但仅返回类型不同不足以成为函数的重载
原理:名字改编
-
名字改编实际上是将函数名与参数列表(参数个数、顺序、类型)结合在一起定义成了新函数
-
显然C语言不支持,而C++支持,C++兼容C时不会按照此方式对其库函数进行名字改编
-
extern “C”{ }花括号内不进行名字改编,将代码在C++中按照C方式编译
(但是在gcc中不识别extern,但可以使用C++内置宏,#ifdef __cplusplus,C与C++混合编程)
#ifdef __cplusplus//C++的编译标志宏 extern "C" { #endif int add(int x,int y){ return x+y; } #ifdef _cplusplus } #endif
默认参数
-
C++可以给函数定义默认参数值。通常,调用函数时,要为函数的每个参数给定对应的实参。
-
void func(int x=0,int y=0);
(当函数有声明和定义,默认参数通常放在声明中,防止调用时编译器还没检查到定义,不知道设置了默认参数)
-
必须从右往左设置,不能交叉,因为参数入栈的顺序也是从右往左,赋值是从左往右
-
默认参数涵盖了比它参数个数更少的某一类函数的重载,不允许再次定义更小的同名函数,防止产生二义性
void func();
void func(int x);
void func(int x,int y);
//上面三个可以合成下面一个
void func(int x=0,int y=0);
bool类型
-
用来表示true和false,true和false是字面值
-
非0所有数隐式转换为true,0转换为false
-
所占空间大小为一个字节
inline函数
-
内联函数可以兼具宏定义的特性,在调用时候对函数体进行替换,而不需要使用到栈,能有效降低运行时间
-
inline int add(int a,int b){ }
(必须与函数体定义放在一起才能内联,所以不建议将头文件和实现文件(声明与实现)分开,实在要用加上#include “函数定义.cc”)
-
隐含*const this
-
inline函数的效果和带参数的宏定义是一样的,同时又可以进行编译,安全性比带参数的宏定义要高
-
内联函数是小函数,如果循环、递归多不宜使用
-
内联函数可以进行调试
异常安全
-
异常是程序在执行期间产生的问题,比如除零
-
异常提供了一种转移程序控制权的方式
try{
if(y==0)//语句
throw y;//表达式
}catch(异常类型){
//具体处理
}catch(其他异常类型){
//具体处理
}
-
建议写成0==y,以免出现运算符==和赋值=错误
-
单独使用throw没有效果
字符串
C风格
-
char str1[]=“hello”;
(字符数组写法)
-
char *pstr=“world”
(指针写法)
-
C语言是以‘\0’结尾的
用法1:获取长度
-
size_t len1=strlen(pstr);
(返回字符串的长度不包括末尾‘\0’)
-
size_t len2=sizeof(str1);
(返回字符串的长度包括末尾‘\0’)
-
size_t len3=sizeof(pstr);
(64位机器指针需要8个字节)
(printf中使用**%lu打印长度**)
用法2:拼接字符串
#include<string.h>
#include<stdlib.h>
size_t len = len1+len2-1;
char *pstr1 = static_cast<char *>(malloc(len));
memset(pstr1,0,len);
strcpy(pstr1,str1);//将str1复制到pstr,注意是否内存踩踏
strcat(pstr1,str2);//将str2拼接在pstr1后面
printf("pstr1 = %s\n",pstr1);
-
char*是一个常量指针即const char*,内容不可改
(调试使用printf调试大法)
用法3:比较两个字符串
-
strcmp(str1,str2);
(相同返回0,大于返回正数,小于返回负数)
用法4:查找子串
-
strchr(str1,str2);
(查找str1中子串str2第一次出现的位置,没有则返回空指针)
C++风格
- C风格字符串使用时程序员需要考虑字符数组大小的开辟和结尾空字符的处理,比较麻烦,所以有了C++的string字符串
#include<string>
using std::string;
//C风格可以转换为C++风格(隐式类型转换)
string str1 = "hello world";
string str2("hello world");
//C++风格也可以转换为C风格字符串
char str1[] = str2.c_str();
//遍历打印
for(size_t idx=0; idx!=str.size(); idx++)
cout<<str[idx]<<" ";
cout<<endl;
//截取子串
string str1 = str2.substr(pos,len);
用法1:获取长度
-
size_t len1 = str.size();
-
size_t len2 = str.length();
用法2:拼接字符串
- string str = str1 + ‘A’ + str2 +“wuhan”;
用法3:比较两个字符串
-
str1==str2
(相同返回1,不同返回0)
用法4:查找子串
-
str.find(“str1”)
(返回第一次出现的位置,找不到返回string::npos,通常为-1)
程序内存分配方式
程序内存布局
-
程序运行在虚拟内存空间,32位Linux系统为例,寻址空间4G
-
3G-4G 内核 高地址区域
-
0-3G 用户 低地址区域
-
栈区:局部变量,函数参数,编译器自动分配,往低地址延伸,未初始化则赋随机值
-
堆区:一般由程序员分配与释放,不同于数据结构中的堆,往高地址延伸,new/delete
-
读写段:全局变量,静态变量,默认赋初值0
(全局静态区)
-
只读段:常量字符串、函数体
(文字常量区、程序代码区)
-
(在printf中用%p打印地址)
堆栈比较
申请后系统的响应
-
栈剩余空间大于申请,系统为程序提供内存,否则栈溢出
-
堆首先查空闲内存地址链表分给程序,另外对于大多数系统首地址记录本次分配的大小
申请大小的限制
-
栈是连续的内存区域,VS默认1M
-
堆不连续,受限于有效的虚拟内存
存储内容
-
栈存储主函数的下一条指令,然后是各个参数从右往左入栈,最后是局部变量
-
堆头部用一个字节存放堆的大小,具体内容以及回收都由程序员安排
申请效率
- 栈由编译器自动分配快,堆慢且容易产生碎片
类和对象
思想概述
-
C语言:面向过程的语言,按照事物的发展顺序进行
-
-
C++语言:面向对象的语言,四大基本特征——抽象、封装、继承、多态
-
定义格式
-
万物皆对象,将具有相同属性的对象抽象成类
-
类是对象的封装,对象是类的实例
-
类→对象
-
数据成员→属性
-
成员函数→操作属性的方法
-
class 类名
{
public://公有数据成员和成员函数
int func();
protected://保护子类
private://用来封装数据成员和成员函数
};
-
对象与对象进行交互使得彼此之间状态发生变化
-
类的内部是指花括号之间,在类之外不能访问private数据成员与成员函数,这体现了封装的思想
-
类的声明就是对成员函数的声明,类的定义就是对成员函数的定义
//可在类的外部定义成员函数,即声明在内实现在外)
int 类名:: func(){ }
-
头文件与实现文件分开放在头文件与实现文件中进行编译
-
在类的内部实现的成员函数是inline函数,分开写时不是inline函数
#ifndef "Computer.h"
#include <iostream>
//头文件类定义,其中写上声明
#endif
struct与class
-
C++对struct进行了扩展,功能与class几乎相同
-
唯一的区别,就是默认访问权限不同。class的默认访问权限是private,struct 的默认访问权限是public
代码规范
-
头文件先自定义再C后C++
-
注释位置放前面相邻位置
-
定义一个类各单词首字母大写,先公有再保护后私有
-
成员函数用小写动词开头加首字母大写的名词
-
数据成员命名下划线加小写名词