当前位置: 首页 > news >正文

C++ 对C的扩展

作用域运算符

符号

::

作用

1.当局部变量与全局变量重名时,区分局部变量与全局变量

        变量名        局部变量

        ::变量名        全局变量

2.指明使用的变量所属的命名空间

        命名空间名::变量名

3.实现函数的声明与定义分离

        如:   

                  namespace E{

                                void   method();//函数的声明

                }

                     void  E::method02()  //函数定义

                {

                }

如:C中代码

#include <stdio.h>
int num = 10;
int main(int argc, char const *argv[])
{
int num = 20;
printf(" 局部变量 num = %d\n",num);
// c 语言中当局部变量与全局变量重名时 , 因为就近原则 , 默认使用的是局部变量
// 此时无法使用全局变量
return 0;
}

如:C++代码

#include <iostream>
using namespace std;
int num = 10;
int main(int argc, char const *argv[])
{
int num = 20;
cout << " 局部变量 num = " << num << endl;
cout << " 全局变量 num = " << ::num << endl;
return 0;
}

namespace与using

namespace

含义

命名空间

语法

namespace  空间名

{

             //变量

            //函数

}

注意

1.命名空间只能全局范围内定义(必须定义在函数外)

2.命名空间可嵌套命名空间

3.命名空间是开放的,即可以随时把新的成员加入已有的命名空间中

4.声明和实现可分离

5.无命名空间,意味着命名空间中的标识符只能在本文件内访问

6.命名空间别名

示例1

#include <iostream>
using namespace std;
namespace A{
int a = 1;
int b = 11;
char c = 'A';
}
namespace B{
int a = 2;

int b = 22;
char c = 'B';
}
// 命名空间可以嵌套
namespace C
{
int a = 4;
namespace D{
int a = 5;
}
}
// 命名空间是开放的,即可以随时把新的成员加入已有的命名空间中
// 不能在次定义相同的变量
namespace A{
int d = 111;
}
namespace E{
// 命名空间中可以定义函数
void method01()
{
cout << "method01" << endl;
}
// 声明和实现可分离
void method02();
}
void E::method02()
{
cout << "method02" << endl;
}
// 无名命名空间
namespace{
int a = 6;
}
int main(int argc, char const *argv[])
{
int a= 3;
cout << "A a = " << A::a << endl;
cout << "B a = " << B::a << endl;
cout << "a = " << a << endl;
cout << "C a = " << C::a << endl;
cout << "D a = " << C::D::a << endl;
cout << "A d = " << A::d << endl;
cout << " 无名 a = " << ::a <<endl;
E::method01();
E::method02();
return 0;
}

示例2

#include <iostream>
using namespace std;
namespace A{
int a = 1;
}
int main(int argc, char const *argv[])
{
// 命名空间别名
namespace A1 = A;
cout << "A a = " << A::a << endl;
cout << "A1 a = " << A1::a << endl;
return 0;
}

using

作用

声明可使得指定的标识符可用

语法

1.声明命名空间中单个变量

        using 命名空间名::变量名;

2.声明命名空间中单个函数

        using 命名空间名::函数名;

3.声明整个命名空间

        using namespace 命名空间名;

示例

#include <iostream>
using namespace std;
namespace A{
int i = 10;
char c = 'A';
void methodA()
{
cout << "methodA" << endl;
}
}
// 声明命名空间中的单个变量
// 声明后在使用该变量就可以直接使用
using A::i;
// 声明命名空间中的单个函数
// 声明后在使用该函数就可以直接使用
using A::methodA;
// 声明整个命名空间
// 声明后整个命名空间中所以内容都可直接使用
using namespace A;
int main(int argc, char const *argv[])
{
cout << "A i = " << A::i << endl;
cout << "A i = " << i << endl;
methodA();
cout << "A c = " << c << endl;
return 0;
}

注意

using遇到函数重载,using声明就声明了这个重载函数的所有集合
重载:
同一片空间中,函数名相同,形参列表不同,成为重载
C语言不支持重载
C++支持重载
使用using声明或using编译指令会增加命名冲突的可能性

全局变量检测增强

如:C

#include <stdio.h>
int a;//c 语言编译器会认为此处为变量的声明
int a;
int a = 10;// 变量的定义与初始化
int main(int argc, char const *argv[])
{
return 0;
}

如:C++

#include <iostream>
using namespace std;
int a;//c++ 编译器将此处理解为变量的定义
//int a = 10;// 此时将会重复定义 , 程序无法编译通过
int main(int argc, char const *argv[])
{
return 0;
}

C++中所有的变量和函数都必须有类型

如:c

#include <stdio.h>
void fun(i)
{
printf("fun\n");
}
void fun02()
{
printf("fun02\n");
}
int main(int argc, char const *argv[])
{
fun(10);
fun02();
return 0;
}

如:c++

#include <iostream>
using namespace std;
//c++ 中变量必须有类型 , 此时 i 没有类型所有无法编译通过
// void fun(i)
// {
// }
// 形参中的 void 表示没有形参列表
void fun02(void)
{
cout << "fun02\n";
}
int main(int argc, char const *argv[])
{
fun02();
return 0;
}

严格的类型转换

如:c编译通过

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
int *nums = calloc(10,sizeof(int));
return 0;
}

如:c++,必须强转

#include <iostream>
#include <stdlib.h>
using namespace std;
int main(int argc, char const *argv[])
{
int *nums = (int *)calloc(10,sizeof(int));
return 0;
}

struct类型加强

c中定义结构体变量需要加上struct关键字,c++不需要

c中的结构体只能定义成员变量,不能定义成员函数。c++即可以定义成员变量,

也可以定义成员函数

示例

#include <iostream>
using namespace std;
struct Person{
char name[50];
int age;
void eat()
{
cout << name << " 吃面条 " << endl;
}
void game();
};
void Person::game()
{
cout << name << " 玩游戏 " << endl;
}
int main(int argc, char const *argv[])
{
//c 语法
struct Person p1 = {"tom",18};
//c++ 语法 , 定义结构体变量时可以不用写 struct 关键字
Person p2 = {"jek",18};
p1.eat();
p2.eat();
p1.game();
return 0;
}

新增bool类型

关键字

bool        数据类型

true        真

false        假

true(转换为整数 1)和false(转换为整数 0)

bool类型的变量取值:true或false

bool 类型赋值时,非0值会自动转换为true(1),0值会自动转换false(0)

注意

c 语言中也有 bool 类型,在 c99 标准之前是没有 bool 关键字, c99 标准已经有
bool 类型,包含头文件 stdbool.h, 就可以使用和 c++ 一样的 bool 类型。

示例

#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
cout << true + 0 << endl;
cout << false + 0 << endl;
bool tag = true;
tag = false;
tag = 10;
cout << tag << endl;
return 0;
}

三目运算符功能增强

c 语言三目运算符返回的是值
c++ 三目运算符返回的是变量

如:c

#include <stdio.h>
int main(int argc, char const *argv[])
{
int a = 10;
int b = 1;
//c 语言中三目返回的是值 , 不是变量
int c = a > b ? a : b;
// 所以三目在 c 中不能作为左值 , 无法通过编译
(a > b ? a : b) = 100;
return 0;
}

如:c++

#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int a = 10;
int b = 1;
//c++ 中三目返回的是变量 , 不是值
int c = a > b ? a : b;
// 所以三目在 c++ 中可以作为左值
(a > b ? a : b) = 100;
cout << "a = " << a << endl;
return 0;
}

c/c++中的const

全局变量

c

#include <stdio.h>
const int num = 10;
int main(int argc, char const *argv[])
{
//const 修饰的变量不能重新赋值
//num = 1;
// 无法进行修改 , 因为 num 的值存储在常量区
int *p = #
*p = 1;
printf("num = %d\n",num);
printf("*p = %d\n",*p);
return 0;
}
// 出现段错误

c++

#include <iostream>
using namespace std;
const int num = 10;
int main(int argc, char const *argv[])
{
//num = 1;
int *p = (int *) #
*p = 1;
cout << "num = " << num << endl;
cout << "*p = " << *p << endl;
return 0;
}
// 出现段错误
#include <iostream>
using namespace std;
struct Person
{
int age;
};
const Person p = {2};
int main(int argc, char const *argv[])
{
Person *p1 = (Person *)&p;
p1->age = 10;
cout << "p.age = " << p.age << endl;
return 0;
}

局部变量

c

#include <stdio.h>
int main(int argc, char const *argv[])
{
const int num = 10;
//const 修饰的变量不能重新赋值
//num = 1;
// 可以进行修改 , 因为 num 的值存储在栈区
int *p = #
*p = 1;
// 修改完成后 num 的值也将被修改
printf("num = %d\n",num);
printf("*p = %d\n",*p);
return 0;
}

c++

#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
// c++ const 修饰的变量会存储在常量表中
const int num = 10;
//num = 1;
// 当我们对常量表的中的变量区地址时 , 系统会开辟一片内存 , 使其存储其变量的值
int *p = (int *) #
// 此时使用指针对其修改 , 修改的是新开辟的内存中的值
*p = 1;
// 此时 num 的值依旧从常量表中获取 , 值并没有发生改变
cout << "num = " << num << endl;
cout << "*p = " << *p << endl;
return 0;
}
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int a = 10;
// c++ const 修饰的变量以其他变量初始化 , 会为其分配内存空间
const int num = a;
//num = 1;
int *p = (int *) #
*p = 1;
// 此时 num 的值依旧从常量表中获取 , 值发生改变
cout << "num = " << num << endl;
cout << "*p = " << *p << endl;
return 0;
}
#include <iostream>
using namespace std;
struct Person
{
int age;
};
int main(int argc, char const *argv[])
{
const Person p = {2};
//const 修饰自定义类型的变量 , 无法修改其自定义变量中的成员变量
//p.age = 10;
// 无法获取其成员变量的地址
//int *p = &(p.age);
//const 修饰的自定义类型的变量 , 无法获取其地址 , 因为地址是使用 const 数据类
* 修饰的
// 转换后就可以使用该指针修改其自定义类型中的成员变量
Person *p1 = (Person *)&p;
p1->age = 10;
cout << "p.age = " << p.age << endl;
return 0;
}

总结(重点)

全局变量:c/c++没区别,会出现段错误

局部变量:

        1.如果const修饰的普通类型的变量,使用常量初始化
                如:
                        const int a=10;
                        此时会生成符号表,当获取其变量的地址时会开辟新的地址,使用获取的地址
修改其值,不会影响符号常量表中的数据
        2.如果const修饰的普通类型的变量,使用变量初始化
                如:
                        int x=10;
                        const int a=x;
                        此时不会生成符号常量表,会直接开辟地址,获取的地址修改其值,会修改其内容
3.如果const修饰的是自定义变量
1.无法直接修改其自定义类型中的成员变量
2.无法获取自定义类型中的成员变量的地址
3.获取其自定义类型变量的地址需强转,强制过会就可以使用改地址修改其
成员变量的值

建议

尽量以 const 替换 #define
const #define 的区别
1 const 有类型,可进行编译器类型安全检查。 #define 无类型,不可进行类型
检查 .
2 const 有作用域,而 #define 不重视作用域,默认定义处到文件结尾 . 如果定
义在指定作用域下有效的常量,那么 #define 就不能用

引用(重要)

英文名:reference

符号:

&

作用

给已有变量起别名

语法

基本数据类型

        数据类型  &变量名A=变量B;

        给变量B取别名叫变量A

        此时操作A就是在操作B,操作B就是在操作A

数据类型

        方式1:

                typedef  数组的数据类型  类型别名[数组长度]

                类型别名  &别名=数组名;

        方式2:

                数组的数据类型(&别名)[数组长度]=数组名;

        注意:此时数组长度不能忽略不写

指针

        数据类型  *&别名=指针变量名;

常量

        const  数据类型  &别名=变量名;

注意

1.不能返回局部变量的引用

2.函数当左值,必须返回引用。

本质

引用的本质在c++内部实现是一个指针常量

Type& ref = val; // Type* const ref = &val;

#include <iostream>
using namespace std;
struct Stu
{
int age;
};
// void test(Stu s)
// {
// s.age = 10;
// }
void test(Stu &s)
{
s.age = 10;
}
int main(int argc, char const *argv[])
{
Stu stu = {1};
test(stu);
cout << "stu.age = " << stu.age << endl;
return 0;
}

内联函数

语法

inline 返回值类型 函数名 ( 形参列表 )
{
函数体
}

特点

内联函数:在编译阶段像宏一样展开。
作为类的成员函数 , 有作用域的限制
内联函数为了继承宏函数的效率,没有函数调用时开销,然后又可以像普通函数那样,
可以进行参数,返回值类型的安全检查,又可以作为成员函数。

注意

1,inline只能在定义函数的时候修饰。

2, 任何在类内部定义的函数自动成为内联函数。
3,inline 修饰的函数是否为内联函数,取决于编译器。对于非 inline 修饰的函数,也
有可能转成内联函数(体积小、功能简单的函数)。

条件

不能存在任何形式的循环语句
不能存在过多的条件判断语句
函数体不能过于庞大
不能对函数进行取址操作

宏函数和内联函数区别(重要)

宏函数(带参宏)
        参数没有类型,不能保证参数的完整型。
        宏函数  在预处理阶段展开
        宏函数  没有作用域限制  不能作为类的成员
内联函数:
        参数有类型   保证参数的完整性
        内联函数  在编译阶段  展开。
        内联函数  有作用域限制  能作为类的成员

对函数的加强

形参默认值

语法

返回值类型 函数名 ( 数据类型 变量名 1 = , 数据类型 变量名 2 = ,...)
{
函数体
}

注意

形参中有默认值的参数,在函数调用时可传可不传,如果不传使用默认值
调用有默认值的函数,传入实参依据会按形参的顺序赋值
如果某个形参有默认值,其后的形参必须也有默认值

形参占位符

void test(int a,int,int)
{
}

注意

1, 形参占位符可以有多个
2, 可以在形参的任意位置

重载

函数名相同,形象列表不同,称为重载
多态的一种体现

              

                       
        

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 西瓜书学习笔记三 归纳偏好
  • python(6) : 读取pdf的文本, 读取pdf每一页为文件
  • 详细介绍pytorch重要的API
  • 靠谱是性价比最高的社交名片:一个靠谱的人往往有这4种品质!
  • 算法的学习笔记—二叉树的镜像(牛客JZ27)
  • Spring 中ConfigurableBeanFactory
  • Redis的热key以及Big(大)key是什么?如何解决Redis的热key以及Big(大)key问题?
  • arcgis打开不同tif格式编码的栅格数据
  • 【卡码网Python基础课 21.图形的面积】
  • 高速信号的眼图、加重、均衡
  • Spire.PDF for .NET【文档操作】演示:检测 PDF 文件是否为 Portfolio
  • Airtest 的使用
  • 对比state和props的区别?
  • C语言——操作符详解
  • C++ STL sort_heap 用法
  • 【Leetcode】101. 对称二叉树
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • magento2项目上线注意事项
  • SQLServer之索引简介
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 微服务入门【系列视频课程】
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • 【干货分享】dos命令大全
  • ​MySQL主从复制一致性检测
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • #VERDI# 关于如何查看FSM状态机的方法
  • (10)ATF MMU转换表
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (TOJ2804)Even? Odd?
  • (八)Spring源码解析:Spring MVC
  • (精确度,召回率,真阳性,假阳性)ACC、敏感性、特异性等 ROC指标
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (一)基于IDEA的JAVA基础12
  • .bat批处理(六):替换字符串中匹配的子串
  • .env.development、.env.production、.env.staging
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .Net Core 中间件验签
  • .NET MAUI Sqlite程序应用-数据库配置(一)
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .NET 依赖注入和配置系统
  • .Net+SQL Server企业应用性能优化笔记4——精确查找瓶颈
  • /ThinkPHP/Library/Think/Storage/Driver/File.class.php  LINE: 48
  • @Builder用法
  • @serverendpoint注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • [Algorithm][动态规划][两个数组的DP][正则表达式匹配][交错字符串][两个字符串的最小ASCII删除和][最长重复子数组]详细讲解
  • [Ariticle] 厚黑之道 一 小狐狸听故事
  • [C#]扩展方法
  • [C#]使用C#部署yolov8-seg的实例分割的tensorrt模型
  • [C/C++随笔] char与unsigned char区别
  • [C++初阶]list的模拟实现
  • [CUDA手搓]从零开始用C++ CUDA搭建一个卷积神经网络(LeNet),了解神经网络各个层背后算法原理
  • [datastore@cyberfear.com].Elbie、[thekeyishere@cock.li].Elbie勒索病毒数据怎么处理|数据解密恢复
  • [DAU-FI Net开源 | Dual Attention UNet+特征融合+Sobel和Canny等算子解决语义分割痛点]