c++(一)
- C与C++有什么区别
- 命名空间
- 使用
- 输入输出流
- 引用
- 指针和引用的区别
- 定义
- 拓展
- 函数重载
- 例子
- 测试
- 函数重载原理
- 参数默认值
- 什么是参数默认值
- 注意
- 在c++中如何引入c的库
- 动态内存分配
- new、delete与malloc、free的区别?
C与C++有什么区别
<1>都是编程语言
<2>C是面向过程的,C++是面向对象的
<3>第一个字母都是相同,在C语言中只要是合法的C语言语句,在C++中都是可以使用的(C++完全兼容C)
<4>++:在C的基础上增加了一些新的内容(新特性、关键字、数据类型等等)
<5>C是面向过程的编程语言;C++是面向对象的编程语言!C是注重过程的!C++注重的是结
果!!!C也有在面向对象编程,是通过结构体,但是因为C里面的结构体中只能描述属性,不能有函数,所以面向对象编程不够彻底,引入C++来解决这个问题!
命名空间
理解成是一个容器,可以放数据类型、函数、变量!
为了解决:在C语言中,能出现同名的函数吗?能出现同样的自定义的数据类型吗? 在同一个作用域内能出现同名的变量吗? 都不可以的!
作用:解决命名冲突,命名冲突的情况: 函数、数据类型、变量!
格式: namespace 命名空间的名字
{
函数;
数据类型;
变量
}
namespace s1
{
int count = 10;
struct STU_T
{
int sno;
char name[20];
};
void print()
{
printf("s1中的count=%d\n", count);
}
}
namespace s2
{
int count = 10;
struct STU_T
{
int sno;
char name[20];
};
void print()
{
printf("s2中的count=%d\n", count);
}
}
使用
方法1 命名空间::函数();
int main()
{
//使用方法1
s1::print();
s2::print();
printf("hello world\n");
return 0;
}
方法2 将命名空间搞成全局变量,访问时只需要变量前面加上::(域运算符)
using namespace s1; //切换到这个命名空间中===》把命名空间中的内容做成全局
int main()
{
//使用方法2
::print();
printf("%d\n", count);
//使用方法1
s2::print();
printf("hello world\n");
return 0;
}
输入输出流
流: 以字节为单位, 连续不断,方向统一的。
C中标准输入输出函数: printf()、scanf()、 putchar()、getchar()、 gets()、puts()。这些函数在C++中仍然是可以使用的!除此之外,C++中引入了新的可以做输入输出的方法:
//之前需要引用
#include <iostream>
using namespace std;
输入:cin >> 变量;
输出:cout << 变量;
引用
是一种数据类型,用来给变量起别名
弱化指针(在C中可以用指针来实现的,在C++中都可以使用引用来替换)
减少临时空间的分配
指针和引用的区别
1. 指针可以定义后不初始化,但引用定义后必须初始化;
2. 指针定义时,需要开辟内存空间;引用和变量公用同一块内存空间,不会重新分配内存空间;
3. 指针是存储某个实例的地址;引用是实例的别名
4. 指针变量的值可以为空;引用没有空引用;
5. 理论上指针级数没有限制,但引用只有一级,不存在引用的引用,但可以有指针的指针
6. 不可以对函数的局部变量或对象以引用或者指针的方式返回
7. ++引用与++指针效果不同,对指针变量的操作会使指针指向下一个实体的地址,而不是改变所指实体的内容
8. 对指针变量使用“sizeof”得到的是指针变量的大小,对引用使用“sizeof”得到的是变量的大小
9. 指针变量作为形参时需要测试合法性进行判空,引用不需要判空
10. 指针使用时要加 “ * ”,引用可以直接使用
11. 指针是可以改变指向的; 引用是不可以改变指向的 引用比指针安全
定义
数据类型 &别名 = 变量名;
//注意:引用必须初始化,一旦初始化之后再不能给引用赋值
拓展
int a = 10;
const int &a_pt = a;
a_pt = 20;//error(不能对引用再次赋值)
const int &m = 200;// 等价于 #define m 200
函数重载
解决命名困难的问题
概念:函数功能相似,函数名相同,参数不同,与返回值类型无关的一组函数,互为重载
参数不同: 参数个数不同、参数类型不同、参数类型的顺序不同
例子
#include <iostream>
using namespace std;
int sum(int a, int b)
{
cout << "int,int" << endl;
return a + b;
}
int sum(int a, double b)
{
cout << "int, double" << endl;
return a + b;
}
int sum(double a, int b)
{
cout << "double, double" << endl;
return a + b;
}
int sum(int a)
{
cout << "int" << endl;
return a + 0;
}
double sum(double a, double b)
{
cout << "double, double" << endl;
return a + b;
}
char sum(char a, char b)
{
cout << "char, char" << endl;
return a + b;
}
string sum(string a, string b)
{
cout << "string,string" << endl;
return a + b;
}
int main()
{
//调用的函数名是相同的,只是传入了不同的参数,他根据传入的参数的类型匹配了对应的函数去执行了
cout << sum(5) << endl;
cout << sum(5,6) << endl;
cout << sum(5.3, 6) << endl;
cout << sum(5, 6.8) << endl;
cout << sum(5.3, 6.8) << endl;
cout << sum('A', '\0') << endl;
cout << sum("123", "abc") << endl;
//如上执行了不同的代码块,根据函数调用的原理,说明每一个调用函数的地方,函数地址都是不同的,也就说明
// 函数名应该是不一样的! 函数名不一样,那是因为用的编译器不同了! gcc / g++
return 0;
}
1.函数调用原理:在调用函数的地址其实保存的是函数的地址,执行的时候会根据函数地址到对应的内存空间,然后执行对应的代码块;
2.当代码块执行完之后再返回到调用函数的地址,继续向下执行!
测试
同一个.c文件,分别使用gcc和g++进行编译,使用nm 可执行文件名
gcc编译后的结果,函数名没有变
g++编译后的结果, 函数名发生变化了: 根据函数名的长度、函数名、参数的个数以及参数的类型进行重命名,名字发生了变化,对应函数的地址也就不同,执行的时候就根据不同的地址执行不同代码块!
函数重载原理
使用g++编译后,函数名根据函数名的长度、参数个数、数据类型进行了重命名,函数名变了地址也就
变了,调用时执行的就是不同的函数体
参数默认值
简化代码:
函数重载:当只有参数个数不同的情况下造成的代码冗余
什么是参数默认值
在定义/声明的时候给形参进行初始化
int sum(int a = 0,int b = 0,int c = 0)
注意
- 写默认参数的时候是从右至左,因为调用的时候实参给的顺序是从左至右
- 没有给默认参数传参时,就按默认值处理
- 给默认参数传参时,就按传入的实参进行处理
- 二义性:函数重载有默认参数时
- 解决:保留参数个数最多的,且有默认值的函数
- 当声明和定义同时存在时,参数默认值只能放在函数声明中
在c++中如何引入c的库
以静态库为例
使用gcc编译
使用g++编译
问题:使用g++编译时函数的名称发生了改变
解决:使用g++编译器编译时函数的名称不能发生改变
问题:如何判断是gcc还是g++编译器
方法1:通过宏来判断
__cplusplus
方式2:通过单个字符来测试
在c里面单个字符当做整型来用,长度是四个字节
在c++里面单个字符占一个字节
动态内存分配
在C语言中,使用malloc做动态内存分配, 使用free去做释放!
int main()
{
int* p = nullptr;
p = (int *)malloc(4 * 4);
if (p==nullptr)
{
printf("malloc error\n");
return -1;
}
else
{
memset(p, 0, sizeof(int)*4);
*p = 100;
*(p+1) = 200;
*(p + 2) = 300;
*(p + 3) = 400;
free(p);
}
return 0;
}
在C++中引入新的方式来动态内存分配 new运算符开空间 delete 运算符释放空间
语法:
一块空间分配与释放:
数据类型 *变量 = new 数据类型; //不初始化
delete 变量;
数据类型 *变量 = new 数据类型();//有初始化
delete 变量;
连续空间分配与释放:
数据类型 *变量 = new 数据类型[几块]; //不初始化
delete [] 变量;
数据类型 *变量 = new 数据类型[元素个数]();//括号
int main()
{
int* p = nullptr;
//去堆区分配了4字节的内存空间
p = new int;
cout << *p << endl; // 随机数----没有初始化
int* pp = nullptr;
//去堆区分配了4字节的内存空间
pp = new int(6);
cout << *pp << endl; // 自动进行了初始化,不 传值,默认值为0;传了值进来,就按传进来的值进行初始化
char* ptr = new char[10]; //连续分配了10char类型的空间
cout << ptr << endl;
delete p; //释放一块空间
delete [] ptr; //释放连续空间
return 0;
}
new、delete与malloc、free的区别?
-
new/delete是c++的操作符,而malloc/free是库函数
-
new 在调用时会先为对象分配内存,再调用对象的构造函数,而malloc不会;
delete 在调用时会调用析构函数,而free不会
-
使用malloc为对象指针分配内存,要明确指定分配内存大小,而new不需要
-
new作为操作符,可以被重载,而malloc不行
-
new分配内存成功,则返回对象指针;而malloc分配成功会返回void*类型指针
-
new如果分配内存失败会抛出bad_alloc异常;而malloc分配内存会返回NULL指针
-
new从自由存储区为对象分配内存;malloc从堆上分配内存(自由存储区可以在堆也可以在其他地方(比如静态存储区),这取决于编译器从哪里为new的使用分配内存。)