【C++学习入门】5. 关键字使用

assert const static this inline
函数指针 虚函数 虚表 virtual dynamic_cast
volatile union&bitfield extern struct和class explicit
friend using :: enum decltype
define

assert

#include <stdio.h> 
// assert在这头文件中, 
// 可以在引入这个文件前,通过 #define NDEBUG 禁用断言宏
// #define NDEBUG
#include <assert.h> int main() 
{ int x = 7; x = 9; // 必须x等于7,否则报错,这是一种正向判断,也就是必须这样.否则报错.assert(x==7); return 0; 
} 

const

const常量具有类型,编译器可以进行安全检查;#define宏定义没有数据类型,只是简单的字符串替换,不能进行安全检查
const常量支持所有类型
其他情况下它只是一个 const 限定的变量,不要将与常量混

const char * a; //指向const对象的指针或者说指向常量的指针。
char const * a; //同上
char * const a; //指向类型对象的const指针。或者说常指针、const指针。
const char * const a; //指向const对象的const指针。

这里其实很好理解,将const char 看成一个类型,*a是一个指向const char类型的指针. 因为这个对象类型是常量类型,所以不能变.
* const a 就是用const修饰*a的固定写法. 见到这种,就认为这个指针本身不可变就行了.

其实只需要记住 * const 这种情况,也就是当const在*右边:说明这个指针不能被改变.别的情况都不用记的.

指针换成引用也是一样的道理.

常用例子:

int func(const class & a){};
int getField() const {} // 相当于 getField(const A * const this)

static

static修饰的东西是全局的. 只能存在一个,且有特殊内存空间.

  • static 变量的生命周期与程序的生命周期相同,即在程序运行期间一直存在,而不是在函数调用结束后就被销毁。
  • static 函数的作用域仅限于定义该函数的文件,即只能在该文件中被调用。
  • static 类成员属于整个类,而不是某个对象,因此所有对象共享同一个静态成员。
  • static 成员函数不属于任何类对象或类实例

常用例子:

// 单例
class demo {
public:static demo & instance();
};demo & demo::instance() {static demo ins;return ins;
}
// 需要多个模块共享访问时,也可以使用 static
// 一些小功能,适当使用static,会很方便

this

成员函数的默认参数,相当于rust中的self.

inline

内联,将一些简短的方法,代码贴到别的函数中,这样可以减少一次函数调用.

内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联.因为内联要在编译期,确定代码片段.
常用例子

inline void A::f1(int x){}

sizeof

计算类型大小

  • 类的大小根据成员变量决定,具体是对齐以后的大小.
  • 派生类的大小是基类+派生累的所有成员的大小.
  • 虚函数无论多少个,都是8个字节大小.
class A{};
sizeof(A);

函数指针

可以声明函数指针变量和函数指针类型

// 1. FuncPtr 是一种类型,这种方式很通用.方便.
typedef void (*FuncPtr)(void);void func() { cout << "This is a function." << endl;
}int main() {FuncPtr fp = &func; fp(); return 0;
}
// 2. 如果只是简单使用,直接创建一个函数指针变量用
void func() { cout << "This is a function." << endl;
}int main() {void (*fp)(void) = &func;fp(); return 0;
}

虚函数

  • 使用virtual修饰的函数是虚函数.如果 virtual void func() = 0,则这个函数是纯虚函数.
  • 只有使用virtual修饰的函数,派生类才能使用override重写函数,当然也可以选择不覆盖. 如果要覆盖的话,virtualoverride要成对出现.
class Base {
public:virtual void func() = 0; // 纯虚函数
};class Derived : public Base {
public:void func() override { // 使用 override 修饰符// 实现函数体}
};

虚表是一种用于动态绑定的方式.
rust中通过这种办法,来抹除trait对象的类型.称为动态分发。
每个虚函数对象都有一个指针指向这个虚表。这个虚表里面也存了函数指针,指向存放函数的内存空间。
看上面的图,Derived只重写了Base的func1和func2两个函数。因此Derived类的虚表。

virtual

  • 构造函数不能用 virtual 修饰,因为虚表中的vptr需要再构造期间创建,这段代码是编译器加上去的,如果构造函数是虚函数,则不能创建vptr了.
  • 析构函数可以用 virtual 修饰.并且如果这个类本省就是为了让别的类继承,那么析构函数就应该使用 virtual 修饰.
  • 还有一些偏门的例子,就认为错的就行了,只关注正确的就行了.

正常例子:

// 作为基类
class Base {
public:Base();virtual ~Base();virtual void func() = 0; // 纯虚函数
};

dynamic_cast

多态类型间进行转换,相比C风格的强制类型转换和C++ , reinterpret_castdynamic_cast提供了类型安全检查.

volatile

  • volatile 修饰的变量,编译器不会去优化.
  • volatile 修饰的变量,每次都会去内存中读取,而不是读寄存器中的值.
// 1. 编译器进行优化
int  *output = (unsigned  int *)0xff800000; //定义一个IO端口;  
int  init(void)  {  int i;  for(i=0;i< 10;i++){  *output = i;  }  
}
// 优化成了这个
int  init(void)  
{  *output = 9;  
}
// 2. 必须从内存中读取
int square(volatile int *ptr) { int a,b; // 第一次从内存中读取 ptra = *ptr; // 第二次从内存中读取 ptr,ptr的值可能已经被别处代码改掉了.b = *ptr; return a * b; 
}
// 所以可以改成这样,或者去掉 volatile 也可以.
int square(volatile int *ptr) { int a;a = *ptr; return a * a; 
}

union和bitfield

union是一种特殊的类,里面的变量公用一个空间,有些类似rust中的枚举.

union u_box {struct box st_box;     unsigned int ui_box;
};

bit field重新定义变量大小,需要的时候再去查

struct _PRCODE
{unsigned int code1: 2;unsigned int cdde2: 2;unsigned int code3: 8;
};

extern

C++支持函数重载,C++函数编译后生成的符号带有函数参数类型的信息,而C则没有。

例如int add(int a, int b)函数经过C++编译器生成.o文件后,add会变成形如add_int_int之类的, 而C的话则会是形如_add, 就是说:相同的函数,在C和C++中,编译后生成的符号不同。

这就导致一个问题:如果C++中使用C语言实现的函数,在编译链接的时候,会出错,提示找不到对应的符号。此时extern "C"就起作用了:告诉链接器去寻找_add这类的C语言符号,而不是经过C++修饰的符号。

// c语言中不支持extern "C",只有 extern.
extern "C" {int add(int x,int y);
}

struct和class

两者区别不大,cpp中,struct和class都可以有析构函数,都可以继承和多态.
struct中默认权限是public,class中默认权限是private的.
struct定义基类和派生的例子:

struct Shape {virtual double area() const = 0;
};struct Circle : public Shape {double radius;Circle(double r) : radius(r) {}double area() const override {return 3.14 * radius * radius;}
};

explicit

explicit 修饰构造函数时,可以防止隐式转换和复制初始化
explicit 修饰转换函数时,可以防止隐式转换,但按语境转换除外

  • todo: 后面要仔细梳理一下这个类型转换问题.

friend

友元提供了一种 普通函数或者类成员函数 访问另一个类中的私有或保护成员 的机制. 感觉很不好, 代码结构会非常乱. 了解一下,不用这东西.

class A{
public:A(int _a):a(_a){};// 类B是类A的友元,那么类B可以直接访问A的私有成员friend class B;
private:int a;
};

using

using 可以引入标识符(如函数名、变量名等).引入就是从其定义所在的作用域引入到当前作用域中,使得当前作用域中也可以使用该标识符.
它的基本用法是:

using 标识符(如函数名、变量名等)
using 别名 = 类型

例子:

// 1. 使用命名空间
using namespace std;
// 2. 取别名,类似c中的typedef 
typedef vector<int> V1; 
using V2 = vector<int>;

还有一些偏的用法,了解就行

// 1. 改变访问权限,私有继承,却可通过 using来访问
class Derived : private Base {public:using Base::size;protected:using Base::n;
};
// 2. 重载,这里有两个f函数.Derived对象调用f(),会调用base中的f()方法.
class Derived : private Base {public:using Base::f;void f(int n){cout<<"Derived::f(int)"<<endl;}
};

::

  • 全局作用域符(::name):用于类型名称(类、类成员、成员函数、变量等)前,表示作用域为全局命名空间
  • 类作用域符(class::name):用于表示指定类型的作用域范围是具体某个类的
  • 命名空间作用域符(namespace::name):用于表示指定类型的作用域范围是具体某个命名空间的
int count1=0;    // 全局(::)的countclass A {
public:static int count2;  // 类A的count (A::count)
};int A::count2;
::count1=1; // 设置全局的count1为1
A::count2=2; // 设置类A的count2为2

enum

枚举类型是一种类型,值的内存布局和整数一样,默认从0开始填充.但是是另外一种类型,所以和整数不能相互赋值.

// 值分别为7、1、2、3、4、5、6。
// 可以进行赋值和关系运算(==,>=等),以及标准输出.
enum week {Sun=7, Mon=1, Tue, Wed, Thu, Fri, Sat};
cout << week::Sun << endl; 

枚举类,有了区域限制 ,但类中不能有方法.

enum class week {Sun=7, Mon=1, Tue='a', Wed, Thu, Fri, Sat};
// 98
cout << static_cast<int>(week::Wed) << endl;
// b
cout << static_cast<char>(week::Wed) << endl;

decltype

判断表达式的类型decltype (expression)

int i = 4;
decltype(i) a; //推导结果为int。a的类型为int。
// 与using/typedef合用
using size_t = decltype(sizeof(0));
// 泛型
template <typename T>
auto multiply(T x, T y)->decltype(x*y)
{return x*y;
}
  • todo: 左值右值这些.如果e是一个被重载的函数,则会导致编译错误。 否则 ,假设e的类型是T,如果e是一个将亡值,那么decltype(e)为T&& 否则,假设e的类型是T,如果e是一个左值,那么decltype(e)为T&。 否则,假设e的类型是T,则decltype(e)为T。

define

定义一段字符,在引用的地方替换掉.
不到万不得已,不去用宏.

#define PI 3.1415926
// 宏定义中的参数必须用括号括起来,以避免优先级问题
#define MAX(a, b) ((a) > (b) ? (a) : (b))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/425445.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

尤雨溪推荐的拖拽插件,支持Vue2/Vue3 VueDraggablePlus

大家好,我是「前端实验室」爱分享的了不起~ 今天在网上看到尤雨溪推荐的这款拖拽组件,试了一下非常不错,这里推荐给大家。 说到拖拽工具库,非大名鼎鼎的的 Sortablejs 莫属。它是前端领域比较知名的,且功能强大的工具。但我们直接使用Sortablejs的情况很少,一般都是使用…

【Redis】之Geo

概述 Geo就是Geolocation的简写形式&#xff0c;代表地理坐标。在Redis中&#xff0c;构造了能够存储地址坐标信息的一种数据结构&#xff0c;帮助我们根据经纬度来检索数据。 命令行操作方法 GEOADD 可以用来添加一个或者多个地理坐标。 GEODIST 返回一个key中两个成员之…

【专题】2024跨境出海供应链洞察-更先进供应链报告合集PDF分享(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p37665 当前&#xff0c;全球化商业浪潮促使跨境电商行业飞速发展&#xff0c;产业带与跨境电商接轨、平台半托管模式涌现、社交电商带来红利机会以及海外仓不断扩张&#xff0c;这使得产业带外贸工厂、内贸工厂、传统进出口企业和品…

自制一键杀死端口进程程序# tomcat 如何杀死tomcat进程

直接cmd 窗口执行如下命令即可 netstat -ano | findstr :8080 taskkill /F /PID <PID>简简单单的两个指令,总是记不住,也懒的记, 每次端口冲突的时候, 都是直接查百度,很苦逼, 如果有一个程序,直接输入端口号,点击按钮直接杀死进程,岂不爽歪歪. 跟我一起制作一个屠猫的…

【D3.js in Action 3 精译_022】3.2 使用 D3 完成数据准备工作

当前内容所在位置 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可视化最佳实践&#xff08;下&#xff09;1.4 本章小结 第二章…

【网络原理】❤️Tcp 常用机制❤️ —— 延时应答,捎带应答, 面向字节流, 异常情况处理。保姆式详解 , 建议收藏 !!!

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

[数据集][目标检测]无人机识别检测数据集VOC+YOLO格式6986张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;6986 标注数量(xml文件个数)&#xff1a;6986 标注数量(txt文件个数)&#xff1a;6986 标注…

‌内网穿透技术‌总结

内网穿透是一种网络技术&#xff0c;通过它可以使外部网络用户访问内部网络中的设备和服务。一般情况下&#xff0c;内网是无法直接访问的&#xff0c;因为它位于一个封闭的局域网中&#xff0c;无法从外部访问。而通过内网穿透&#xff0c;可以将内部网络中的设备和服务暴露在…

数据稀缺条件下的时间序列微分:符号回归(Symbolic Regression)方法介绍与Python示例

时间序列概况在日常生活和专业研究中都很常见。简而言之,时间序列概况是一系列连续的数据点 y(0), y(1), …, y(t) ,其中时间 t 的点依赖于时间 t-1 的前一个点(或更早的时间点)。 在许多应用中,研究者致力于预测时间序列概况的未来行为。存在各种建模方法。这些模型通常基于过…

Unity让摄像机跟随物体的方法(不借助父子关系)

在Unity中&#xff0c;不使用子对象的方式让相机跟随物体移动&#xff0c;我们通过编写脚本来实现。下面放一个从工程中摘出来的的C#脚本示例&#xff0c;用于将相机绑定到一个Target对象上并跟随其移动&#xff1a; using UnityEngine; public class FollowCamera : MonoBeh…

DPDK基础入门(十):虚拟化

I/O虚拟化 全虚拟化&#xff1a;宿主机截获客户机对I/O设备的访问请求&#xff0c;然后通过软件模拟真实的硬件。这种方式对客户机而言非常透明&#xff0c;无需考虑底层硬件的情况&#xff0c;不需要修改操作系统。 半虚拟化&#xff1a;通过前端驱动/后端驱动模拟实现I/O虚拟…

【STM32】CAN总线基础入门

CAN总线基础入门 一、CAN简介二、主流通信协议对比三、CAN物理层1、CAN硬件电路2、CAN电平标准3、CAN收发器 – TJA1050&#xff08;高速CAN&#xff09;4、CAN物理层特性 四、帧格式1、CAN总线帧格式2、数据帧&#xff13;、数据帧各部分用途简介&#xff14;、数据帧的发展历…

大模型参数高效微调技术原理综述(八)-MAM Adapter、UniPELT

MAM Adapter 背景 近年来提出了多种参数高效的迁移学习方法&#xff0c;这些方法仅微调少量&#xff08;额外&#xff09;参数即可获得强大的性能。虽然有效&#xff0c;但人们对为什么有效的关键要素以及各种高效微调方法之间的联系知之甚少。 下图展示了不同的微调方法&am…

小米,B站网络安全岗位笔试题目+答案

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 《Java代码审…

坚持的力量--完成向CSDN迁移500篇技术文章阶段小记-以此自勉

前言&#xff1a;本文为迁移前的博客中的文章《坚持的力量-写给第1000篇文章笔记》发表于 publish:May 14, 2021 -Friday&#xff0c;作为原个人博客中累计写满1000篇文章的总结和鼓励。因在向CSDN迁移文章的过程中进行了一些文章合并等调整&#xff0c;总文数大量下降&#xf…

ACM模式下算法题输入输出攻略【C++】

文章目录 [TOC] 1. 核心代码模式与ACM模式1.1 ACM模式介绍1.2 注意事项 2. C常用的输入输出方法2.1 输入2.1.1 cin注意事项2.1.2 getline()注意事项2.1.3 getchar()注意事项 2.2 输出 3. 案例3.1 一维数组输入3.1.1 固定长度的一维数组3.1.2 不固定长度的一维数组 3.2 二维数组…

使用ddns-go实现自动配置IPv6的DDNS

正文共&#xff1a;888 字 17 图&#xff0c;预估阅读时间&#xff1a;1 分钟 前面说到通过PPPoE拨号获取到的IPv6地址没有发生变化&#xff08;企业路由器配置IPv6家用宽带的PPPoE拨号示例&#xff09;&#xff0c;结果说完就打脸了。中间家里停了一次电&#xff0c;路由器重新…

Transformer模型详细步骤

Transformer模型是nlp任务中不能绕开的学习任务&#xff0c;我将从数据开始&#xff0c;每一步骤都列举出来&#xff0c;然后对应重点的代码进行讲解 ------------------------------------------------------------------------------------------------------------- Trans…

物品识别——基于python语言

目录 1.物品识别 2.模型介绍 3.文件框架 4.代码示例 4.1 camera.py 4.2 interaction.py 4.3 object_detection.py 4.4 main.py 4.5 运行结果 5.总结 1.物品识别 该项目使用Python&#xff0c;OpenCV进行图像捕捉&#xff0c;进行物品识别。我们将使用YOLO&#xff08…

re题(23)BUUFCTF-[FlareOn4]login

BUUCTF在线评测 (buuoj.cn) 下载后打开看到是一个txt和一个html 分别打开看看&#xff0c;txt是提示&#xff0c;html应该就是要破解的网页 打开网页&#xff0c;查看源代码 找到程序&#xff0c;变灰的部分是关键&#xff0c;是指如果是前13个字母就加13&#xff0c;如果是…