C++ 对 C 语言的提高
命令空间简单使用
引用命令空间的三种方式:
- 直接指定标识符。例如
std::cout<<"hello"<<std::endl;
;
使用using
关键字。例如using std::cout;
; - 导入整个命令空间。例如
using namespace std;
导入std
命名空间;
#include <iostream>
//定义一个命令空间
namespace space1{
int a = 100;
int b = 200;
}
//using namespace std;
//只导入其中的 cout 和 endl
using std::cout;
using std::endl;
int main(int argc, char const **argv)
{
cout<<"hello"<<endl;
using namespace space1;//直接导入命令空间
cout<<a<<" "<<b<<endl;
return 0;
}
const
关键字的加强
C
语言中的const
是一个冒牌货,即使用来修饰变量的值不能修改,但是还是可以通过指针指向这个变量,然后修改指针指向的内存来修改这个变量的值;- 注意
const
和#define
的区别: ①#define
只是在预编译时进行字符置换,例如#define PI 3.14
,这里的PI
不是变量,没有类型,不占用存储单元。②而const float PI = 3. 14
定义了常变量PI
,它具有变量的属性,有数据类型,占用存储单元,只是在程序运行期间变量的值是固定的,不能改变(真正的不能改变);
测试:
#include <iostream>
int main(int argc, char const **argv)
{
//a 此时是一个真正的常量 : 不能通过指针修改(C 语言中的 const 是一个冒牌货)
const int a = 100;
//如果对一个常量取地址,编译器会临时开辟一个空间 temp,让这个指针指向 temp
int *p = (int *)&a; //注意要强制转换一下
*p = 200;
printf("a = %d, *p = %d\n", a, *p);
//可以使用 const 定义的"常量"来定义数组(C 语言中不能这样)
int arr[a]; //ok
return 0;
}
输出(可以看到 a
没有改变( C
语言中会变)):
a = 100, *p = 200
引用-重点
- 变量名,本身是一段内存的引用,即别名(
alias
). 引用可以看作一个已定义变量的别名; - 对变量声明一个引用,并不另外开辟内存单元,例如
int &b = a
,则b
和a
都代表同一个内存单元(使用sizeof()
测a
、b
大小是相同的)。引用与被引用的变量有相同的地址; - 在声明一个引用时,必须同时初始化(和常量有点类似),即声明它代表哪一个变量;
- 当声明一个变量的引用后,改引用一直与其代表的变量相联系,不能再作为其他变量的别名。
&
符号前有数据类型时,是引用。其他都是代表取地址;- 引用所占用的大小跟指针是相等的,引用可能是一个"常指针"(
int *const p
); - 对引用的初始化,可以是一个变量名,也可以是另一个引用。如
int a = 3; int &b = a; int &c = b;
此时,整形变量a
有两个别名b
、c
; - 不能建立
void
类型的引用(但是有void *
类型指针(万能指针))。不能建立引用的数组(可以有指针数组);
使用经典的 swap
问题来看引用作为形参的简单使用:
#include <stdio.h>
//值传递(不行)
int swap1(int a, int b){
int t = a;
a = b;
b = t;
}
//指针(也是值传递)
int swap2(int *a, int *b){
int t = *a;
*a = *b;
*b = t;
}
//引用(引用传递)
int swap3(int &a, int &b){
int t = a;
a = b;
b = t;
}
int main(int argc, char const **argv)
{
int a = 100, b = 200;
swap1(a, b);
printf("a = %d, b = %d\n", a , b);
swap2(&a, &b);
printf("a = %d, b = %d\n", a , b);
swap3(a, b);
printf("a = %d, b = %d\n", a , b);
return 0;
}
输出:
a = 100, b = 200
a = 200, b = 100
a = 100, b = 200
指针引用
可以建立指针变量的引用,如:
int a = 5;
int *p = &a;
int* &ref = p; //ref 是一个指向 “整形变量的指针变量” 的引用,初始化为 p
下面看一个使用指针引用的例子,对比使用二级指针和使用指针引用的区别:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Student{
int age;
char name[20];
};
//通过二级指针
void getMem(Student **temp){
Student *p = (Student *)malloc(sizeof(Student));
p->age = 13;
strcpy(p->name, "zhangsan");
*temp = p;
}
//通过引用
void getMem2(Student* &p){ //将 Student*看成一个类型
p = (Student *)malloc(sizeof(Student));
p->age = 14;
strcpy(p->name, "lisi");
}
//通过指针
void free1(Student **temp){
Student *p = *temp;
if(p != NULL){
free(p);
*temp = NULL;
}
}
//通过指向指针的引用
void free2(Student* &p){ //指向指针的引用
if(p != NULL){
free(p);
p = NULL;
}
}
int main(int argc, char const **argv)
{
Student *p = NULL;
getMem(&p);
printf("age = %d, name = %s\n", p->age, p->name);
free1(&p);
printf("------------------\n");
getMem2(p);
printf("age = %d, name = %s\n", p->age, p->name);
free2(p);
return 0;
}
输出:
age = 13, name = zhangsan
------------------
age = 14, name = lisi
没有引用指针
- 由于引用不是一种独立的数据类型,所以不能建立指向引用类型的指针变量。
- 但是,可以将变量的引用的地址赋值给一个指针,此时指针指向的是原来的变量。
例如:
int a = 3;
int &b = a;
int *p = &b; //指针变量 p 指向变量 a 的引用 b,相当于指向 a,合法
上面代码和下面一行代码相同:
int *p = &a;
输出 *p
的值,就是 b
的值,即 a
的值。
不能定义指向引用类型的指针变量,不能写成:
int& *p = &a; //企图定义指向引用类型的指针变量,错误
const
引用
- 如果想对一个常量进行引用,必须是一个
const
引用; - 可以对一个变量进行 常引用(此时引用不可修改,但是原变量可以修改)。这个特征一般是用在函数形参修饰上,不希望改变原来的实参的值;
- 可以用常量或表达式对引用进行初始化,但此时必须用
const
作声明(内部是使用一个temp
临时变量转换);
测试:
#include <stdio.h>
#include <iostream>
using namespace std;
int main(int argc, char const **argv)
{
//对一个常量进行引用
const int a = 10;
//int& ref1 = a; //err
const int &ref1 = a; //ok
//可以对一个变量进行 常引用(此时引用不可修改,但是原变量可以修改)
//这个特征一般是用在函数形参修饰上,有时候不希望改变原来的实参的值
int b = 10;
const int& ref2 = b;
//ref2 = 20; //err
b = 20; // ok
printf("b = %d, ref2 = %d\n", b, ref2);
//对表达式做引用
// 内部系统处理 int temp = c+10; const int& ref3 = temp;
int c = 30;
const int& ref3 = c + 10; //合法
//也可以对不同类型进行转换
double d = 3.14;
const int& ref4 = d; // int temp = d; const int& ref4 = temp
cout<<d<<" "<<ref4<<endl;//b = 3.14,ref4 = 3
return 0;
}
输出:
b = 20, ref2 = 20
3.14 3
默认参数、函数重载、作用域运算符
- 如果全局和局部有相同名字变量,使用
::
运算符来操作全局变量;
默认参数要注意: 如果默认参数出现,那么右边的都必须有默认参数,也就是只有参数列表后面部分的参数才可以提供默认参数值; - 函数重载规则: ①函数名相同。②参数个数不同,参数的类型不同,参数顺序不同,均可构成重载。 ③返回值类型不同则不可以构成重载。
- 一个函数,不能既作重载,又作默认参数的函数。
简单使用:
#include <stdio.h>
int fun(int a, int b = 20, int c = 30){
return a + b + c;
}
int a = 100;
int main(int argc, char const **argv)
{
// 作用域运算符 ::
int a = 200;
printf("a = %d\n", a);
printf("a2 = %d\n", ::a); //全局的 a
printf("%d\n",fun(10));
printf("%d\n",fun(10, 10));
printf("%d\n",fun(10, 10, 10));
return 0;
}
new
、 delete
的使用
C
语言中使用malloc
函数必须指定开辟空间的大小,即malloc(size)
,且malloc
函数只能从用户处知道应开辟空间的大小而不知道数据的类型,因此无法使其返回的指针指向具体的数据类型。其返回值一律为void *
,使用时必须强制转换;C++
中提供了new
和delete
运算符来替代malloc
和free
函数;- 差别:
malloc
不会调用类的构造函数,而new
会调用类的构造函数。②free
不会调用类的析构函数,而delete
会调用类的析构函数;(析构函数释放的是对象内部的内存,而delete
释放的是对象,而delete
也出发析构,所以都可以释放)
例如
new int; //开辟一个存放整数的空间,返回一个指向整形数据的指针
new int(100); //开辟一个存放整数的空间,并指定初始值为 100
new char[10]; // 开辟一个存放字符数组的空间,size = 10
new int[5][4];
float *p = new float(3.14); //将返回的指向实型数据的指针赋给指针变量 p
delete p;
delete []p; //释放对数组空间的操作(加方括号)
简单测试:
#include <stdio.h>
int main(int argc, char const **argv)
{
// new 和 delete 使用
int *p1 = new int(10);
printf("*p1 = %d\n", *p1);
delete p1;
int *p2 = new int[10];
for(int i = 0;i < 10; i++)
p2[i] = i;
for(int i = 0;i < 10; i++)
printf("%d ",p2[i]);
printf("\n");
delete []p2;
return 0;
}
输出:
*p1 = 10
0 1 2 3 4 5 6 7 8 9
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

上一篇: Lambda 表达式总结
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论