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

C到C++入门基础知识

一:命名空间:namespace

(一):命名空间的定义

注:命名空间只能定义在全局,不能定义在函数内部。

(1)类似于C语言的结构体,C语言的命名空间定义为:

namespace  name{    // name是命名空间的名字
//  
}

(2)命名空间里成员可以是:变量/函数/自定义类型变量/类,等。

namespace xs {int age;char name[10];int ID;struct xs{int height;char* hobies;};void swap(int* num1,int*num2){int tmp = *num1;*num1 = *num2;*num2 = tmp;}
};

(3)命名空间可以嵌套定义:

namespace xs {int age;char name[10];int ID;struct xs{int height;char* hobies;};void swap(int* num1,int*num2){int tmp = *num1;*num1 = *num2;*num2 = tmp;}// 嵌套一个老师的命名空间namespace teacher {char* subject;int work_year;char* name;}
};

(4)在不同文件中定义同一个名字相同的命名空间会被编译器识别为同一个命名空间:

例如同一个项目中分别有两个.cpp文件,两个文件都有xs这命名空间,在编译的时候不会报错,编译器会将他们识别为同一个命名空间。

(5)C++的标准库的命名空间是std(standard).

 

(二):命名空间的使用

我们在命名空间中定义了变量,函数,类或者结构体等,如果我们没有解析命名空间,像C语言一样使用命名空间的对象和方法时会报错:

namespace xs {int age;char name[10];int ID;struct xs{int height;char* hobies;};void swap(int* num1,int*num2){int tmp = *num1;*num1 = *num2;*num2 = tmp;}namespace teacher {char* subject;int work_year;char* name;}
};int main()
{int a = 1;int b = 2;swap(&a, &b);return 0;
}

9657b2921ed74033a3facb4309b4d3ea.png

在使用命名空间域内定义的变量的时候有以下几种方法:

(1)指定命名空间访问:

:: 符号被称为作用域解析运算符

#include <stdio.h>namespace xs {int age;char name[10];int ID;struct xs{int height;char* hobies;};void swap(int* num1,int*num2){int tmp = *num1;*num1 = *num2;*num2 = tmp;}namespace teacher {char* subject;int work_year;char* name;}
};int main()
{int a = 1;int b = 2;// 这里指定xs这个命名空间域xs::swap(&a, &b);printf("a = %d \nb = %d", a, b);return 0;
}

(2)使用using关键字将命名空间中的某个成员展开

#include <stdio.h>namespace xs {int age;char name[10];int ID;struct xs{int height;char* hobies;};void swap(int* num1,int*num2){int tmp = *num1;*num1 = *num2;*num2 = tmp;}namespace teacher {char* subject;int work_year;char* name;}
};// 展开xs中的swap函数
using xs::swap;
int main()
{int a = 1;int b = 2;// 这里我们去掉xs::不会报错swap(&a, &b);printf("a = %d \nb = %d", a, b);return 0;
}

(3)使用using关键字展开命名空间中的全部成员:这种方式容易产生命名冲突等问题

#include <stdio.h>namespace xs {int age = 10;char name[10] = "小明";int ID;struct _xs{int height;char* hobies;};void swap(int* num1,int*num2){int tmp = *num1;*num1 = *num2;*num2 = tmp;}namespace _teacher {char* subject;int work_year;char* name;}
};// 展开命名空间中的全部成员,可以不用域解析::就可以随便访问命名空间内的所有成员了
using namespace xs;
int main()
{printf("age:%d\n name:%s", age, name);return 0;
}

(三):为什么要使用命名空间

(1).解决C语言命名冲突问题

(2).命名空间的本质是开出一个独立的域空间,C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑,所以有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的⽣命周期,命名空间域和类域不影响变量⽣命周期。

二:输入输出:cout / cin

说明:cout和cin是c++的标准输入输出类的对象,他们是标准库<iostream>中定义的,用于窄字符(narrowcharacters(oftypechar))的输入输出。

(1)同C语言相比cout和cin不需要格式化,他们支持任意类型的输入输出,会自动将其他类型转换成字符串类型

(2)cout/cin/(换行endl)等都被定义于C++标准库<iostream>,因为C++标准库都放在std(standard)的命名空间中,所以使用的时候要解析命名空间。

(3)有些编译器<iostream>会间接包含printf和scanf函数,也就是说不包含<stdio.h>头文件也可以使用这两函数。

#include <iostream>using namespace std;int main()
{int age;char name[10];cin >> age >> name;// 这里没有包含<stdio.h>printf也可以正常使用printf("age:%d\tname:%s\n", age, name);cout << age << endl;cout << name << endl;return 0;
}

三:缺省参数

定义:在定义函数的时候给予参数一个默认的缺省值。

(1)半缺省,全缺省。

半缺省:部分形参给予默认值。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。

全缺省:全部形参给予默认值。

(2)带缺省参数的函数调⽤,C++规定必须从左到右依次给实参,不能跳跃给实参。

(3)含缺省参数的函数调用的时候,没有传参使用默认值,传参使用传递值。

#include <iostream>// 半缺省
int Add1(int b, int c, int a = 0)
{return a + b + c;
}// 全缺省
int Add2(int a = 0, int b = 0)
{return a + b;
}using namespace std;int main()
{int n1 = 2;int n2 = 3;cout << Add1(n1,n2) << endl;// 全缺省的cout << Add2() << endl;return 0;
}

(4)函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。

我们将.c文件的两个函数声明放到,h文件.c文件依然给缺省值8f8a9847e9b44ce5b500273610911e81.png

c9e273398e5a42238c16faf218486518.png

编译器报错:

7ae3d12f5ce34d989c529e305d8102ba.png

所以应该将.c文件中的缺省参数去掉

四:内联函数:inline

使用inline关键字修饰的函数被调用时会在调用处将函数定义展开

(1)加上inline的函数,如果函数代码较多或者是递归,编译器会忽视不展开代码。

(2)使用inline的本质是替换函数调用,提高程序执行的效率(因为函数调用需要建立函数栈帧,开辟空间等消耗),可以平替C语言的宏。

(3)inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错

使用inline,直接在函数的前面加个inline就可以了。

inline int add(int a, int b)
{return a + b;
}

五:函数重载

函数重载:即同名函数,提现了类的多态行为。

满足函数重载的条件:

1.函数的形参不同

2.函数的参数个数不同

3.形参的类型不同

4.形参类型顺序不同

// 函数的形参不同以及形参个数不同
int add(int a, int b,int c = 1)
{return a + b;
}
double add(double a, double b, int c = 1)
{return a + b + c;
}// 形参不同和形参类型顺序不同
void func(char c, int n)
{cout << c << "  " << n << endl;printf("形参不同\n");}void func(int n, char c)
{cout << c << "  " << n << endl;printf("形参类型顺序不同\n");
}int main()
{// 名字一样调用的是两个函数func('a', 4);func(4, 'a');cout << add(1, 2) << endl;cout << add(1.0, 2.0, 3) << endl;return 0;
}

b14bec1fb64c401b9589f9c4333c295d.png

但是返回值不同不可以

c50de625aa3b434f8a3a763d719865fa.png

六:引用

(一)引用的定义和特性

(1)引用就是给一个对象起别名,不开辟内存空间。

其基本格式为:类型& 引⽤别名 = 引⽤对象; (这里的&不是取地址)

#include <iostream>
using namespace std;int main()
{int a = 0;int c = 5;int& ra = a;int& rc = c;// 对引用进行++ra++;rc++;cout << "ra++后a:" << a << endl;cout << "rc++后c:" << c << endl;cout << "ra的地址为:" << &ra << endl;cout << "a的地址为:" << &a << endl;cout << "rc的地址为:" << &rc << endl;cout << "c的地址为:" << &c << endl;return 0;
}

146e630148c84f279d9fc2f7be1276ff.png

(2)引用定义的时候必须要初始化:看吧。

86ada2d0b9424c2dbe4b86a709d61100.png

(3)⼀个变量可以有多个引⽤:跟一个人有多个绰号差不多

#include <iostream>
using namespace std;int main()
{int a = 0;int c = 5;int& ra = a;int& rra = a;int& rc = c;return 0;
}

(4)引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体:

(5)引用可以引用引用;

int a = 0;int& ra = a;// 这样是可以的
int& rra = ra;

(二)引用的使用

(1)引⽤在实践中主要是于引⽤传参和引⽤做返回值中减少拷⻉提⾼效率和改变引⽤对象时同时改变被引⽤对象

例如在函数传参的时候

void fun(int& x)
{x++;
}int main()
{int a = 0;fun(a);// 这里相当于将a取了一个别名,然后函数里面根据这个别名找到对应的对象进行运算cout << a << endl;return 0;
}

(三)const修饰引用

(1)const修饰引用可以使权限缩小,但是不能使权限放大,当然const修饰的应用对象是不能被修改的。

// 定义一个变量
const int a = 8;// 权限放大,不允许,会报错的
int& ra = a;// 权限平替,这样可以
const int& ra = a;int b = 0;
// 权限缩小
int& rb = b;
// 不允许
rb++;
// 允许
b++;// 权限缩小只是缩小引用的权限缩小,而不会影响引用的对象的权限。

(2)引用可以引用临时对象:

临时对象:在程序运行中产生的用于转换的值或者其他对象,例如:类型转换,函数传参(函数传参是临时拷贝,传地址就不会产生临时对象)。这期间就会产生临时对象。

临时对象具有常性:

void fun(int& x)
{x++;
}void fun2(int x)
{int& rx = x;x++;cout << rx << endl; // 这输出3
}int main()
{int a = 0;fun(a);// 这里相当于将a取了一个别名,然后函数里面根据这个别名找到对应的对象进行运算cout << a << endl;const int n = 2;int rn = n;n++;  // 这里不允许// 这里int向double转换的时候产生了临时变量,权限被放大了。const double& rm = n * 3;// n是const修饰的变量,传递给函数,传递的是它的一份临时拷贝fun2(n);cout << rm << endl; // 这里输出6return 0;
}

(四)指针和引用的区别

(1)指针需要开辟空间,指针变量存储的是空间的地址。引用不需要开空间,他是所引用对象的另一个别名。

dc2f10bc354e417faf31eeed4c043eb5.png

(2)引用定义的时候就必须要初始化,指针可以不用

int& r;// 指针不初始化没问题,编译器不会初始化,但是这样就成了野指针,不建议这样搞
int* ptr;

(3)指针容易出现空指针和野指针,引用不容易出现空引用,引用比指针更安全。

空引用:

 

(4)引⽤可以直接访问指向对象,指针需要解引⽤才是访问指向对象。

(5)引⽤在初始化时引⽤⼀个对象后,就不能再引⽤其他对象;⽽指针可以在不断地改变指向对象。

int main()
{int a = 0;int& b = a;int d = 5;b = d;int* p = &a;cout << p << endl;p = &d;cout << p << endl;cout << "a和b的地址" << endl;cout << &a << endl;cout << &b << endl;return 0;
}

5e923efd384345de9d2b8b66b171c14b.png

(6)sizeof中含义不同,引⽤结果为引⽤类型的⼤⼩,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8byte)

七:nullptr和NULL的区别

NULL在C++中被定义为了宏0,容易导致和整型的0混淆使用,而nullptr不会出现这种情况,C语言支持NULL不支持nullptr。C++都支持。

int main()
{// 这里明着给int类型的a赋值指针但是没报错int a = NULL;printf("%d", a);return 0;
}

48b55ddc46494f01964169fa51ad5642.png

 

 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 数据结构基础讲解(八)——树和二叉树专项练习(上)
  • 【LLM:Gemini】文本摘要、信息提取、验证和纠错、重新排列图表、视频理解、图像理解、模态组合
  • windows检查端口占用并关闭应用
  • springboot 整合 nacos 配置实现多个环境不同配置
  • Mysql 视图存储过程触发器
  • TCP客户端编码和解码处理:发送和接收指定编码消息
  • 速通GPT:《Improving Language Understanding by Generative Pre-Training》全文解读
  • 【字幕】恋上数据结构与算法之012复杂度07leetcode
  • 小程序——生命周期
  • 【Unity基础】如何选择脚本编译方式Mono和IL2CPP?
  • 数据驱动的生态系统架构:打造智能化管理与业务增长的未来战略
  • 强烈建议!所有Python基础差的同学,死磕这本64页的背记手册
  • go语言后端开发学习(七)——如何在gin框架中集成限流中间件
  • 系统编程-初识MCU
  • 滚雪球学SpringCloud[2.2]:Consul与Zookeeper服务注册
  • 【Leetcode】101. 对称二叉树
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • 03Go 类型总结
  • 10个最佳ES6特性 ES7与ES8的特性
  • HTML中设置input等文本框为不可操作
  • input实现文字超出省略号功能
  • Median of Two Sorted Arrays
  • October CMS - 快速入门 9 Images And Galleries
  • PermissionScope Swift4 兼容问题
  • Python_OOP
  • WordPress 获取当前文章下的所有附件/获取指定ID文章的附件(图片、文件、视频)...
  • 阿里云应用高可用服务公测发布
  • 读懂package.json -- 依赖管理
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 使用common-codec进行md5加密
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • # 透过事物看本质的能力怎么培养?
  • ###C语言程序设计-----C语言学习(6)#
  • #include<初见C语言之指针(5)>
  • $.ajax()
  • (35)远程识别(又称无人机识别)(二)
  • (分布式缓存)Redis持久化
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (面试必看!)锁策略
  • (十六)串口UART
  • (四)activit5.23.0修复跟踪高亮显示BUG
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (一)Neo4j下载安装以及初次使用
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (转)关于pipe()的详细解析
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • (自用)仿写程序
  • .gitignore
  • .NET基础篇——反射的奥妙
  • /proc/stat文件详解(翻译)
  • [000-01-018].第3节:Linux环境下ElasticSearch环境搭建
  • [100天算法】-每个元音包含偶数次的最长子字符串(day 53)