首页 > 编程语言 >14_C++对c的扩展

14_C++对c的扩展

时间:2023-10-05 22:05:19浏览次数:39  
标签:10 14 int void 扩展 c++ C++ cout 函数

c++对c的扩展

::作用域运算符

::使用全局变量

using namespace std;
int a = 10;
void test01()
{
  int a = 20;
  cout << a << endl; //20
  cout << ::a << endl; //10
}

命名空间 namespace

namespace和c语言中static只在本源文件中有效差不多

命名空间使用语法

创建一个命名空间

namespace A{
  int a = 10;
}
namespace B{
  int a = 20;
}
void test(){
  cout << A::a << endl; //10
  cout << B::a << endl; //20
}

命名空间可嵌套

namespace A{
  int a = 10;
  namespace B{
    int a = 20;
  }
}
void test(){
  cout << A::a << endl; //10
  cout << A::B::a << endl; //20
}

命名空间是开放的,可以将新成员添加入命名空间

namespace A{
  int a = 10;
}
namespace A{
  void func(){
    cout << "hello namespace!" << endl;
  }
}
void test(){
  cout << A::a << endl;
  A::func();
}

声明和实现可分离

namespace MySpace{
  void fun1();
  void fun2();
}
void MySpace::fun1(){
  cout << "MySpace::fun1" << endl;
}
void MySpace::fun2(){
  cout << "MySpace::fun2" << endl;
}

无名命名空间

意味着命名空间中的标识符只能在本文件中访问, 相当于给这个标识符加上了static,使其可以作内部连接

namespace{
  int a = 10;
  void func(){
    cout << "hello namespace" << endl;
  }
  void test(){
    cout << "a : " << a << endl;
    func();
  }
}

命名空间别名

namespace veryLongName{
  int a = 10;
  void func(){
    cout << "hello namespace" << endl;
  }
}
void test(){
  namespace shortName = veryLongName;
  cout << "veryLongName::a" << shortName::a << endl;
  veryLongName::func();
  shortName::func();
}

using 声明命名空间中的成员 可用

使用using声明后可以直接用 A::a -> a

namespace A{
  int paramA = 20;
  itn paramB = 30;
  void funcA(){
    cout << "hello funcA" << endl;
  }
  void funcB(){
    cout << "hello funcB" << endl;
  }
}
void test(){
  cout << A::paramA << endl;
  A::fucA();
  
  //using声明成员可用
  using A::paramA;
  using A::funcA;
  cout << paramA << endl;
  funcA();
}

using声明成员碰到函数重载

using声明包含函数重载

namespace A{
  void func(){}
  void func(int x){}
  void func(int x, int y){}
}
void test(){
  using A::func;
  func();
  func(10);
  func(10, 20);

using声明整个命名空间

using声明整个命名空间不会和局部变量发生冲突, 但会与其他命名空间发生冲突

namespace A{
  int paramA = 20;
  int paramB = 30;
  void funcA(){
    cout << "hello funcA" << endl;
  }
  void funcB(){
    cout << "hello funcB" << endl;
  }
}
void test1(){
  using namespace A;
  cout << paramA << endl;
  cout << paramB << endl;
  funcA();
  funcB();
  
  //不会和局部变量发出冲突
  int paramA = 10;
  cout << paramA << endl;
}
namespace B{
  int paramA = 20;
  int paramB = 30;
  void funcA(){
    cout << "hello funcA" << endl;
  }
  void funcB(){
    cout << "hello funcB" << endl;
  }
}
void test2(){
  using namespace A;
  using namespace B;
  cout << paramA << endl; //error 发生冲突
}

struct类型增强

c中定义结构体变量需要加上struct关键字,c++不需要。c中的结构体只能定义成员变量,不能定义成员函数。c++即可以定义成员变量,也可以定义成员函数。

结构体中即可以定义成员变量, 也可以定义成员函数

struct Student{
  string mName;
  int mAge;
  void setName(string name){
    mName = name;
  }
  void setAge(int age){
    mAge = age;
  }
  void showStudent(){
    cout << "Name:" << mName << " Age:" << mAge << endl;
  }
}

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

void test01(){
  Student student;
  student.setName("John");
  student.setAge(20);
  student.showStudent();
}

bool类型关键字

标准c++的bool类型有两种内建的常量true(转换为整数1)和false(转换为整数0)表示状态。这三个名字都是关键字。bool类型只有两个值, true(1值), false(0值) bool类型占1个字节大小 给bool类型赋值时,非0值会自动转换为true(1),0值会自动转换false(0)

void test(){
  cout << sizeof(false) << endl; //1 因为bool类型占一个字节
  bool flag = true;
  flag = 10; //非0值自动为true, 0值为false
}

引用(reference)

在c/c++中指针的作用基本都是一样的,但是c++增加了另外一种给函数传递地址的途径,这就是按引用传递(pass-by-reference)。变量名实质上是一段连续内存空间的别名,是一个标号(门牌号)程序中通过变量来申请并命名内存空间通过变量的名字可以使用存储空间1对一段连续的内存空间只能取一个别名吗? c++中新增了引用的概念,引用可以作为一个已定义变量的别名。

引用的定义

本质: 给变量取个别名

定义步骤:

1&别名

2给哪个变量取别名, 就定义该变量

3从上往下整体替换

普通变量的引用

void test01(){
    int a = 10;
    int &b = a; //别名b, 不开辟额外空间
}

image-20230923173924777

数组的引用

int arr[5] = {10, 20, 30, 40, 50};
int n = sizeof(arr)/sizeof(arr[0]);
int (&myarr)[5] = arr;
for(int i=0;i<n;i++)
{
    cout << myArr[i] << " ";
}
cout << endl;

指针变量的引用

int num = 10;
int *p = &num;
int *(&myp) = p;
cout << *p << endl;
cout << *myp << endl;

函数的引用

void fun01()
{
    cout << "fun01" << endl;
}

void (&myfun)() = fun01;
myfun();

引用作为函数的参数

函数内部可以通过引用操作外部变量

void swap01(int *p1, int *p2)
{
    int tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}
void swap02(int &x, int &y)
{
    int tmp = x;
    x = y;
    y = tmp;
}
int main()
{
    int a = 10;
    int b = 20;
    cout << a << ", " << b << endl; //10, 20
    //swap01(&a, &b);
    swap02(a, b);
    cout << a << ", " << b << endl; //20, 10
}

引用作为函数返回值

不要返回普通局部变量的引用

int& getData()
{
	int num = 10;
    return num; //返回时局部变量已释放
}
int main()
{
    int &b = getData(); //操作已释放的变量有问题
}

返回值类型为引用 可以完成链式操作

struct Stu
{
    Stu& printStu(Stu &ob, int value)
    {
        cout << value << " ";
        return ob;
    }
};
int main()
{
    Stu ob1;
    ob1.printStu(ob1, 100).printStu(ob1, 200).printStu(ob1, 300); //100 200 300
}

常饮用

给常量取别名, 不能通过常饮用 修改内容

//int &a = 10; //error
const int &a = 10;
a = 10;//error

常饮用 作为 函数参数: 防止函数内部修改外部的值

void printInt(const int &a)
{
    //a = 200; error
    cout << a << endl;
}
int main()
{
    int num = 100;
    printInt(num); //100
}

内联函数

声明内联函数

内联函数必须在定义时使用inline, 不能在声明时使用inline

int my_add(int x, int y);
int main()
{
    cout << myAdd(100, 200) << endl;
}
//内联函数
inline int myAdd(int x, int y)
{
    return x+y;
}

特点: 在编译阶段 将内联函数中的函数体 替换函数调用处, 避免函数调用时的开销

宏函数和内联函数区别

宏函数和内联函数 都会在适当的位置 进行展开 避免函数调用开销。

宏函数在预处理阶段展开,内联函数在编译阶段展开.

宏函数的参数没有类型,不能保证参数的完整性,内联函数的参数有类型 能保证参数的完整性。

宏函数没有作用域的限制,不能作为命名空间、结构体、类的成员内联函数有作用域的限制,能作为命名空间、结构体、类的成员

内联函数的注意事项

在内联函数定义的时候加inline修饰

类中的成员函数 默认都是内联函数(不加inline 也是内联函数)

有时候就算加上inline也不一定是内联函数(内联函数条件)

不能存在任何形式的循环语句

不能存在过多的条件判断语句

函数体不能过于庞大

不能对函数取地址

有时候不加inline修饰也有可能是内联函数。

内不内联 由编译器决定。

函数重载

函数重载底层实现

void func(){}
void func(int x){}
void func(int x, char y){}

以上在linux生成的编译后的函数名为

_Z4funcv //v 代表void,无参数
_Z4funci //i 代表参数为int
_Z4funcic //i 第一个参数int, c 第二个参数char

函数的默认参数

void TestFunc01(int a = 10, int b = 20){
    cout << a+b << endl;
}

注意点:

1一个参数设置默认值, 它后面的参数也要设值

void TestFunc02(int a, int b = 10, int c = 20){}

2如果函数声明和函数定义分开, 函数声明设置了默认参数, 函数定义不能再设置默认参数

void TestFunc03(int a = 0, int b = 0);
void TestFunc03(int a, int b){}

默认参数和函数重载同时出现时注意二义性

void func(int x){}
void func(int x, int y = 10){}
int main(){
    func(10); //error
}

占位参数

声明函数时, 可以设置占位参数, 只有参数类型没有参数名.

一般情况下, 在函数体内部无法使用占位参数

void TestFunc01(int a, int b, int){
	//函数内部无法使用占位参数
}

占位参数也可以设置默认值

void TestFunc02(int a, int b, int = 20){
    //函数内部任然无法使用占位参数
}
void main()
{
    TestFunc01(10, 20); //error 占位参数也要传值
    TestFunc02(10, 20); //ok
}

extern "C"浅析

C++调用C语言代码

以下在Linux下测试:

c函数: void MyFunc(),被编译成函数:MyFunc

C++函数:void MyFunc(){}.被编译成函数:_Z6Myfuncv

通过这个测试,由于c++中需要支持函数重载,所以c和c++中对同一个函数经过编译后生成的函数名是不相同的,这就导致了一个问题,如果在c++中调用一个使用c语言编写模块中的某个函数,那么c++是根据c++的名称修饰方式来查找并链接这个函数,那么就会发生链接错误,以上例, c++中调用MyFunc函数,在链接阶段会去找Z6Myfuncv,结果是没有找到的,因为这个MyFunc函数是c语言编写的,生成的符号是MyFunc。那么如果我想在c++调用c的函数怎么办?

extern"C"的主要作用就是为了实现c++代码能够调用其他c语言代码。加上extern "C"后,这部分代码编译器按c语言的方式进行编译和链接,而不是按c++的方式。

fun.h

#ifndef MYMODULE_H
#define MYMODULE_H
#include<stdio.h>
#if __cplusplus
extern "C"{
#endif
    extern void func1();
    extern int func2(int a, int b);
#if __cplusplus
}
#endif
#endif

fun.c

#include<stdio.h>
#include"fun.h"

void func1(){
    printf("hello world!");
}
int func2(int a, int b){
    return a+b;
}

main.cpp

#include<iostream>
#include "fun.h"
using namespace std;
int main(){
    func1();
    cout << func2(10, 20) << endl;
    return 0;
}

标签:10,14,int,void,扩展,c++,C++,cout,函数
From: https://www.cnblogs.com/mzx233/p/17743966.html

相关文章

  • 14代i5-14600K现身:多核性能提升多达11%
    14代酷睿桌面端还未发售,就陆续在跑分平台上露出。平台规格为Z790主板、32GBDDR5-5200内存,酷睿i5-14600K的单核成绩为2819,多核成绩为16666,对比酷睿i5-13600K,提升幅度分别是5.7%、11.2%。从页面来看,酷睿i5-14600K的基础频率在3.5GHz,最大睿频尚未得知,预测可能高达5.7GHz-5.9GHz。......
  • C++ 数据结构插入效率学习
    转自:https://blog.csdn.net/breaksoftware/article/details/829478381.总结在头部插入。元素数量>15k时,效率unordered_set>set,unordered_map>map。元素数量<1024时,效率unordered_set>set,map> unordered_map。元素数量<256时,效率unordered_set>set,map> unorder......
  • 2023-2024-1 20231415吴昕洋 《计算机基础与程序设计》第一周学习总结
    这个作业属于哪个课程2023-2024-1-计算机基础与程序设计这个作业要求是什么2023-2024-1-计算机基础与程序设计第一周作业这个作业的目标简单浏览《计算机概论》,提出疑问,并尝试解决问题作业正文https://i.cnblogs.com/posts/edit教材内容·学习总结  ......
  • C++ namespace User_Unauthorized version 1.0.0 is officially released
    CodenamespaceUser_Unauthorized{/***@briefThisisaheaderfileforcompetitiveprogramming.*@authorUser-Unauthorized*@version1.0.0*@date2023-10-5*/typedeflonglongvalueType;typedefstd::vector<......
  • C++ Profiler Introduction [CPU Time Only]
    C++ProfilerIntroduction[CPUTimeOnly]author:LastWhisperdate:2023/10/05ThereareseveralprofilersforC++.Basedonmyresearch,I'vefoundthattracyisthemostpowerful.However,it'schallengingtoconfigure.Toquicklybenchmark......
  • C/C++学习 -- HMAC算法
    1.HMAC算法概述HMAC,全称为HMAC-MD5、HMAC-SHA1、HMAC-SHA256等,是一种在数据传输中验证完整性和认证来源的方法。它结合了哈希函数和密钥,通过在数据上应用哈希函数,生成一个带密钥的散列值,用于验证数据的完整性。HMAC算法广泛应用于网络协议、数字签名、认证和访问控制等领域。2.HM......
  • Luogu CF1469B 题解
    这道题其实并不难。题目大意是这样的:已知两个序列\(r\)和\(b\),求出合并后的最大前缀和。很好发现:答案就是\(r\)和\(b\)各自的最大前缀和之和。但要注意:\(r\)和\(b\)可以什么都不取,因此\(maxa\)和\(maxb\)初始要赋值为\(0\)。ACCode:#include<iostream>using......
  • 【分享】Windows XP N合1转自XP终极珍藏系列2014,个人做了一些xp软件包的添加
    添加的软件包见下图  WindowsXPSP3多合一"终极珍藏"第一版微软于2014/04/08公告停止XP服务支持。意思也就是从此你使用XP将不再收到XP系统漏洞补丁推送当然,如果你不在乎系统漏洞补丁这方面,你的日常应用又必须XP兼容支持,你依然可以安装上安全防卫软件继续长期使用。......
  • Multisim 14.3如何修改默认安装路径及下载
    Multisim14.3默认安装到C盘,而且没有修改安装路径选项,给安装带来了很多不便,经过网络查询、实际操作,成功安装到了D盘,希望对想修改默认安装路径的朋友有所帮助。一、安装前准备工作,以下实操真对初学者,否则可以直接转到最后一页,看一下操作说明。   【rjqjf.com】1、本机以安装到D......
  • 用C++写的一个万用哈希函数模板
    用C++写的一个万用哈希函数模板template<typenameT>inlinevoidhash_combine(size_t&seed,constT&val){seed^=hash<T>()(val)+0x9e3779b9+(seed<<6)+(seed<<2);}template<typenameT,typename......