C++对C的增强

1、作用域运算符

::解决归属问题(谁是谁的谁)
可以优先使用全局变量

在这里插入图片描述

2、命名空间

使用关键字namespace,控制标名称的作用域。

命名空间的本质:对符号常量、变量、函数、结构、枚举、类和对象等等进行封装

1、创建一个命名空间

#include <iostream>
using namespace std;
namespace A {
int data=10;
}
namespace B {
int data=20;
}
int main(){
cout<<"A::data"<<A::data<<endl;
cout<<"B::data"<<B::data<<endl;
return 0;
}

输出结果:

A::data10
B::data20

2、命名空间 只能定义在全局(重要)

在这里插入图片描述

3、命名空间可以嵌套

#include <iostream>
using namespace std;
namespace A {
   int data=10;
   namespace B {
   int data=20;
}
}

int main(){

cout<<"A::data"<<A::data<<endl;
cout<<"A::B::data"<<A::B::data<<endl;
return 0;
}

4、可以随时将新的成员加入命名空间

#include <iostream>
using namespace std;
namespace A {
int data=10;
}
//1000行代码后
namespace A {
void fun(void){
    cout<<"hello A"<<endl;
}
}

int main(){

cout<<"A::data"<<A::data<<endl;
A::fun();
return 0;
}

5、命名空间中函数的声明和实现分开

在命名空间内部声明,在外部实现

namespace B{
void fun1();
void fun2();
}

void B::fun1(){
    cout<<"B中的fun1()"<<endl;

}
void B::fun2(){
        cout<<"B中的fun2()"<<endl;
}

下面这种实现是错误的

namespace B{
void fun1();
void fun2();
}

void fun1(){
    cout<<"B中的fun1()"<<endl;

}
void fun2(){
        cout<<"B中的fun2()"<<endl;
}

6、无名命名空间

无名命名空间相当于static int a=10,只能在本文件下使用

namespace {
int a=10;
}

int main(){
cout<<a<<endl;
return 0;
}

7、命名空间取别名

namespace B{
void fun1();
void fun2();
}

给B起别名为B2

namespace B2=B;
int main(){
    B2::fun1();
return 0;
}

8、使用using申明命名空间中的某几个成员可用

namespace A {
int data=10;
int a=100;
int b=200;
}
int main(){
    using A::a;//申明A命名空间中的a

cout<<"A命名空间中a="<<a<<endl;
return 0;
}

注:当在全局中使用时

using A::a;
int main(){

int a=0;
 cout<<a<<endl;
return 0;
}

打印的是局部变量a=0

int main(){
using A::a;//可以看做局部变量
int a=0;
 cout<<a<<endl;
return 0;
}

程序报错

9、当using遇到函数重载

namespace A {
void fun1(){
    cout<<"fun1()"<<endl;
}
void fun1(int a){
    cout<<"fun1(int)"<<endl;
}
void fun1(int a,int b){
    cout<<"fun1(int,int)"<<endl;
}
}
int main(){
using A::fun1;//函数名即可
fun1();
fun1(1);
fun1(1,2);
return 0;
}

打印结果:

fun1()
fun1(int)
fun1(int,int)

10、using申明整个命名空间

using namespace std;
namespace A {
int a=100;
void fun1(){
    cout<<"fun1()"<<endl;
}
void fun1(int a){
    cout<<"fun1(int)"<<endl;
}
void fun1(int a,int b){
    cout<<"fun1(int,int)"<<endl;
}
}
int main(){
using namespace A;//加上 namespace
 cout<<a<<endl;
fun1();
fun1(1);
fun1(1,2);
return 0;
}

注:①当命名空间中与局部变量重名,先找局部变量

namespace A {
int a=100;
}
int main(){
using namespace A;//加上 namespace
 int a=0;//当 命名空间中与局部变量重名,先找局部变量
 cout<<a<<endl;
return 0;
}

打印结果是0

②当命名空间中的变量与全局变量重名,程序报错

int a=0;
int main(){
using namespace A;//加上 namespace

 cout<<a<<endl;

return 0;
}

error: reference to 'a' is ambiguous
  cout<<a<<endl;
        ^

加上作用域解决

int a=0;
int main(){
using namespace A;//加上 namespace

 cout<<A::a<<endl;//使用的是A中的a
 cout<<::a<<endl;//使用的是全局变量中的a
return 0;
}

所以当使用namespace时,不会和同名局部变量冲突,会和全局同名变量冲突

3、c++对c的增强

1、新增bool类型

2、结构体增强

结构体可以放函数,且给结构体赋值时可以省略struct

示例:

#include <iostream>
using namespace std;
struct student{
    int id;
    char name[30];
    void fun1(){
        cout<<"打游戏"<<endl;
    }
};
int main(){
student lucy={1,"lucy"};
cout<<"id:"<<lucy.id<<"name:"<<lucy.name<<endl;
lucy.fun1();

return 0;
}

3、三目运算符增强

c++三目运算符返回值是引用,c语言返回的是值

int main(){
int a=10;
int b=20;
a>b?a:b=100;
cout<<"a="<<a<<"b="<<b<<endl;//三目运算符返回的是b=100,若是c中 则是10=100
return 0;
}

输出结果:a=10 b=100

4、c++的const 会对变量 优化

1、c++和c中的const都是修饰变量为只读。
2、c语言 严格准许 const修饰的是只读变量

但是在c语言中,可以通过指针对const的值进行修改

const int a=10;
int *p=(int *)&a;
*p=100;
3、c++的const 会对变量优化

1、如果以常量 初始化const修饰的变量 编译器会将变量的值 放入符号常量表中,不会立即给变量开辟空间

在这里插入图片描述

int main(){
const int a=10;
int *p=(int *)&a;
*p=100;
cout<<a<<endl;
return 0;
}

输出结果为10

2、只有当对a 取地址时 编译器才会给a开辟空间(只读变量)

int main(){
const int a=10;
int *p=(int *)&a;
*p=100;//只能修改*p所指向的值,并不能修改符号常量表中的值
cout<<a<<endl;//a=10
cout<<*p<<endl;//*p=100
return 0;
}

3、如果以变量 初始化const修饰的只读变量,没有符号常量表,立即开辟空间

int main(){
    int b=10;
    const int a=b;
    int *p=(int *)&a;
    *p=100;
    cout<<a<<endl;
    cout<<*p<<endl;
return 0;
}

输出结果:

100
100

4、如果以const修饰的是自定义类型的变量 也不会有符号常量表,立即开辟空间

#include <iostream>
#include <cstring>
using namespace std;

struct STU{
    int num;
    char name[30];
};
int main(){
 const STU lucy={100,"lucy"};
 STU *p=(STU *)&lucy;
 p->num=20;
 strcpy(p->name,"lili");
 cout<<p->num<<endl;
 cout<<p->name<<endl;
return 0;
}

输出结果:

20
lili

5、c++中尽量使用 const代替define

①const有类型,可进行编译器类型安全检查。#define无类型,不可进行类型检查
②const有作用域,而#define不重视作用域,宏不能作为命名空间、结构体、类的
成员,而const可以

5、引用

引用的本质:就是给变量名取个别名。
引用定义的步骤:

1 &别名
2 给哪个变量取别名 就定义该变量
3 从上往下整体替换

①给普通变量起别名

int main(int argc, char *argv[])
{
    int a=10;
    int &num=a;
    cout<<"a="<<a<<endl;
    cout<<"num="<<num<<endl;
  int b=20;
  num=b;
  cout<<"a="<<a<<endl;
  cout<<"num="<<num<<endl;

    return 0;
}

打印结果:

a=10
num=10
a=20
num=20

②给数组起别名

int main(int argc, char *argv[])
{
int nums[5]={1,2,3,4,5};
int length=sizeof(nums)/sizeof(nums[0]);
int (&arr)[5]=nums;
for(int i=0;i<length;i++){
cout<<arr[i]<<" ";
}
    return 0;
}

打印结果:

1 2 3 4 5

③给指针变量取别名

int main(int argc, char *argv[])
{
    int a=10;
int *p=&a;
int* &num=p;
cout<<"*p="<<*p<<endl;
cout<<"*num="<<*num<<endl;
    return 0;
}

打印结果:

*p=10
*num=10

④给函数取别名

void fun1(void ){

    cout<<"fun1()"<<endl;
}


int main(int argc, char *argv[])
{
void (&myfun)(void)=fun1;
myfun();
    return 0;
}

⑤作为函数参数

void swap(int &x,int &y){//通过引用实现交换函数
    int temp=x;
    x=y;
    y=temp;

}


int main(int argc, char *argv[])
{
int a=10,b=20;
swap(a,b);
cout<<"a="<<a<<"b="<<b<<endl;
    return 0;
}

节约空间

eg:

struct STU{
    int age;
    char name[6];
};

void fun1(STU stu){//占空间

    cout<<stu.name<<stu.age<<endl;
}
void fun2(STU &stu){//不占空间

    cout<<stu.name<<stu.age<<endl;
}

⑤引用作为函数返回值

int& fun3(){
    int num=100;
    return num;//返回num 外界就是给num取别名
}

int main(int argc, char *argv[])
{
int &b=fun3();//由于num是局部变量在函数执行结束后会回收,所以打印结果为空白
cout<<b<<endl;
    return 0;
}
int& fun3(){
    static int num=100;//使用static延长生命周期
    return num;//返回num 外界就是给num取别名
}

int main(int argc, char *argv[])
{
int &b=fun3();为空白
cout<<b<<endl;
    return 0;
}

链式操作:

struct stut{
    stut& print_stut(stut &s,int age){
        cout<<age<<endl;
        return s;
    }
};

int main(int argc, char *argv[])
{
     stut s1;
s1.print_stut(s1,100).print_stut(s1,200).print_stut(s1,300);
    return 0;
}

输出结果:

100
200
300

⑥常引用

给常量去别名

void test10()
2 {
3 //int &a = 10;//err
4 const int &a = 10;//a就是10的别名
5 //a = 100;//err 不能通过常引用修改内容
6 cout<<a<<endl;
7 }
void fun4(int &arg){//为了节约空间使用了引用
    arg=200;//但是却有被修改的风险
    cout<<arg<<endl;
}
int main(int argc, char *argv[])
{
int num=100;
fun4(num);
    return 0;
}

通过常引用避免这种风险

void fun4(const int &arg){//为了节约空间使用了引用
//    arg=200;error
    cout<<arg<<endl;
}

⑦ 引用的本质

常量指针

int &b = a;//b为a的别名 
int * const b = &a;
b = 100;//a的值为100 *b = 100;

6、内联函数

内联函数:在编译阶段 将内联函数中的函数体 替换函数调用处。避免函数调用时的开销。
内联函数 必须在定义的时候 使用关键字inline修饰, 不能在声明的时候使用inline

int my_add(int x, int y);//函数声明时,不要使用inline

//内联函数 在定义的时候使用inline
inline int my_add(int x, int y)
{
return x+y;
}
1、宏函数和内联函数的区别(重要背)

1、宏函数和内联函数 都会在适当的位置 进行展开避免函数调用开销。
2、宏函数的参数没有类型,不能保证参数的完整性。而内联函数的参数有类型 能保证参数的完整性。
3、宏函数在预处理阶段展开,内联函数在编译阶段展开
4、宏函数没有作用域的限制,不能作为命名空间、结构体、类的成员
内联函数有作用域的限制,能作为命名空间、结构体、类的成员

2、内联函数的注意事项

在内联函数定义的时候加inline修饰
类中的成员函数 默认都是内联函数(不加inline 也是内联函数)
有时候 就算加上inline也不一定是内联函数(内联函数条件)
不能存在任何形式的循环语句
不能存在过多的条件判断语句
函数体不能过于庞大
不能对函数取地址
有时候不加inline修饰 也有可能是内联函数。内不内联 由编译器决定。

7、函数重载

函数重载的条件:
同一作用域,函数的参数类型、个数、顺序不同 都可以重载。(返回值类型不能作为重载的条件)

void printFun(int a)
{
cout<<"int"<<endl;
}
 void printFun(int a, char b)
 {
 cout<<"int char"<<endl;
 }
 void printFun(char a, int b)
 {
 cout<<"char int"<<endl;
}
void printFun(char a)
 {
 cout<<"char"<<endl;
 }

 void test02()
 {
 printFun(10);
 printFun(10, 'a');
 printFun('a', 10);
 printFun('a');
}

8、缺省参数

在函数声明处 给函数参数一个默认的值,如果函数调用处,用户没用传实参,编译器就可以使用这个默认的值。

void sub(int a,int b=10){
    cout<<"a-b="<<a-b<<endl;

}

int main(int argc, char *argv[])
{
sub(20);//10
sub(30,20);//10
    return 0;
}

注意:如果函数的某个参数设置为默认参数, 那么这个参数的右边的所有参数 都必须是默认参数.

案例:一下默认参数正确的是

int func(int a, int b, int c=10);//正确
int func(int a, int b=20, int c);//错误 c必须默认参数
int func(int a=10, int b, int c);//错误 b c必须默认参数
int func(int a, int b=10, int c=20);//正确
int func(int a=10, int b, int c=20);//错误 b必须默认参数
int func(int a=10, int b=20, int c=20);//正确

缺省参数和函数重载同时出现 一定要注意二义性

void sub(int a){
    cout<<"a="<<a<<endl;
}

void sub(int a,int b=10){
    cout<<"a-b="<<a-b<<endl;

}

int main(int argc, char *argv[])
{
sub(20);//上面两个函数都可以调用,出现二义性
return 0;
}

9、占位参数

//没有形参名的形参,叫占位参数

void sub(int a,int ){
    cout<<"a="<<a<<endl;
}
int main(int argc, char *argv[])
{
sub(20,10);
    return 0;
}

占位参数 也可以是缺省参数(默认参数)

void sub(int a,int=10 ){
    cout<<"a="<<a<<endl;

}

int main(int argc, char *argv[])
{
sub(20,10);
    return 0;
}

相关推荐

  1. c/c++】cppc增强 delete 和 delete []区别

    2024-06-06 05:10:05       16 阅读
  2. c++语言增强地方

    2024-06-06 05:10:05       12 阅读
  3. c++扩展C++C扩展

    2024-06-06 05:10:05       13 阅读
  4. C++_C数据类型扩展

    2024-06-06 05:10:05       28 阅读
  5. c/c++】cppc函数扩展

    2024-06-06 05:10:05       12 阅读
  6. c# 路径访问被拒绝

    2024-06-06 05:10:05       35 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-06 05:10:05       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-06 05:10:05       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-06 05:10:05       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-06 05:10:05       18 阅读

热门阅读

  1. sklearn基础教程

    2024-06-06 05:10:05       10 阅读
  2. 2024.6.05总结1102

    2024-06-06 05:10:05       10 阅读
  3. 文档智能开源软件

    2024-06-06 05:10:05       7 阅读
  4. 常用设计模式

    2024-06-06 05:10:05       7 阅读
  5. 层出不穷的大模型产品,你怎么选?【模板】

    2024-06-06 05:10:05       12 阅读
  6. HarmonyOs开发:关系型数据库封装之增删改查

    2024-06-06 05:10:05       8 阅读