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

C++基础问题

C++基础问题

掌握形参默认带缺省值的函数

函数调用时

#include <iostream>int sum(int a, int b = 20) {return a + b;
}int main() {int a = 10, b = 20;int ret = sum(a, b);cout << "ret: " << ret << endl;ret = sum(a);/*a 使用默认值压栈: 时压入 a 的值和 20.push 14Hmov ecx, dowrd ptr[ebp - 4]push ecxcall sum*/ret = sum();// 压入 10 和 20.
}

总的来说,函数效率有所增长:减少一次 push 指令。

带有缺省的函数的声明

// 一个缺省只能被声明一次,并且只能被从右向左声明
#if 1    // 编译通过
int sum(int a = 10, int b = 20);
#elif    // 报错: 默认值只能给一次
int sum(int a = 10, int b = 20);
int sum(int a, int b = 20);
#elif    // 编译通过
int sum(int a, int b = 20);
int sum(int a = 10, int b);
#endifint main() {int a = 10, b = 20;int ret = sum(a, b);cout << "ret: " << ret << endl;ret = sum(a);/*a 使用默认值压栈: 时压入 a 的值和 20.push 14Hmov ecx, dowrd ptr[ebp - 4]push ecxcall sum*/ret = sum();// 压入 10 和 20.
}int sum(int a, int b) {return a + b;
}

掌握内联函数

内联函数和普通函数的区别?

  • 内联函数:在编译过程中没有函数调用的开销,因为在函数的调用点函数被直接展开处理。
  • 内联函数将不再产生相应的函数符号。
  • 函数定义时加上inline并不一定会让函数变成内联函数,仅仅是对编译器的一种建议。如递归很可能不会被处理为内联函数。
#include <iostream>using namespace std;#define IS_INLINE   1#if IS_INLINE
inline 
#endifint sum(int a, int b = 20) {return a + b;
}int main() {int a = 10, b = 20;int ret = sum(a, b);// 此处有标准的函数调用过程// 当函数调用的开销的占比过高,建议使用内联函数cout << "ret: " << ret << endl;}

注意:inline 在 debug 版本上是不起作用的。

验证:inline 在 release 版能出现

chipen@ubuntu:~/code/inlineTest$ cat main.cpp
#include <iostream>using namespace std;int sum(int a, int b) {return a + b;}int main() {int a = 10, b = 20;int ret = sum(a, b);return 0;}
chipen@ubuntu:~/code/inlineTest$ g++ -c main.cpp -O2
chipen@ubuntu:~/code/inlineTest$ objdump -t main.omain.o:     file format elf64-x86-64SYMBOL TABLE:
0000000000000000 l    df *ABS*    0000000000000000 main.cpp
0000000000000000 l    d  .text    0000000000000000 .text
0000000000000000 l    d  .text.startup    0000000000000000 .text.startup
0000000000000000         *UND*    0000000000000000 _ZSt21ios_base_library_initv
0000000000000000 g     F .text    0000000000000008 _Z3sumii    # sum 函数的符号
0000000000000000 g     F .text.startup    0000000000000007 mainchipen@ubuntu:~/code/inlineTest$ vim main.cpp    # 给 sum 函数加上 inline
chipen@ubuntu:~/code/inlineTest$ g++ -c main.cpp -O2
chipen@ubuntu:~/code/inlineTest$ objdump -t main.omain.o:     file format elf64-x86-64SYMBOL TABLE:
0000000000000000 l    df *ABS*    0000000000000000 main.cpp
0000000000000000 l    d  .text.startup    0000000000000000 .text.startup
0000000000000000         *UND*    0000000000000000 _ZSt21ios_base_library_initv
0000000000000000 g     F .text.startup    0000000000000007 main
# 可见,添加内联以后,sum 函数不再有对应的符号,而是被直接替换
chipen@ubuntu:~/code/inlineTest$ g++ -c main.cpp -O0
chipen@ubuntu:~/code/inlineTest$ objdump -t main.omain.o:     file format elf64-x86-64SYMBOL TABLE:
0000000000000000 l    df *ABS*    0000000000000000 main.cpp
0000000000000000 l    d  .text    0000000000000000 .text
0000000000000000 l    d  .text._Z3sumii    0000000000000000 .text._Z3sumii
0000000000000000 l     O .rodata    0000000000000001 _ZNSt8__detail30__integer_to_chars_is_unsignedIjEE
0000000000000001 l     O .rodata    0000000000000001 _ZNSt8__detail30__integer_to_chars_is_unsignedImEE
0000000000000002 l     O .rodata    0000000000000001 _ZNSt8__detail30__integer_to_chars_is_unsignedIyEE
0000000000000000         *UND*    0000000000000000 _ZSt21ios_base_library_initv
0000000000000000  w    F .text._Z3sumii    0000000000000018 _Z3sumii
0000000000000000 g     F .text    0000000000000033 main
# 在只用 -O0 的低优化等级时,inline 需求依然被忽略,可见 inline 只是一种建议行为

函数重载

chipen@ubuntu:~/code/inlineTest$ cat test01.cpp 
#include <iostream>
#include <cstring>using namespace std;bool compare(int a, int b) {cout << "int, int" << endl;return a > b;
}bool compare(double a, double b) {cout << "double, double" << endl;return a > b;
}bool compare(const char *a, const char *b) {cout << "const char*, const char*" << endl;return strcmp(a, b) > 0;
} int main() {compare(10, 20);compare(10.0, 20.0);compare("hello", "world");return 0;
}
chipen@ubuntu:~/code/inlineTest$ ./test01 
int, int
double, double
const char*, const char*

注意1: 一组重载函数指的是: 在同一作用域下的, 函数名相同作用域不同的函数

如当尝试在 main 函数中添加如下声明

chipen@ubuntu:~/code/inlineTest$ cat test01.cpp 
#include <iostream>
#include <cstring>using namespace std;bool compare(int a, int b) {cout << "int, int" << endl;return a > b;
}bool compare(double a, double b) {cout << "double, double" << endl;return a > b;
}bool compare(const char *a, const char *b) {cout << "const char*, const char*" << endl;return strcmp(a, b) > 0;
} int main() {bool compare(int a, int b);compare(10, 20);compare(10.0, 20.0);compare("hello", "world");return 0;
}
chipen@ubuntu:~/code/inlineTest$ g++ test01.cpp -o test01
test01.cpp: In function ‘int main()’:
test01.cpp:26:17: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]26 |         compare("hello", "world");|                 ^~~~~~~|                 ||                 const char*
test01.cpp:23:26: note:   initializing argument 1 of ‘bool compare(int, int)23 |         bool compare(int a, int b);|                      ~~~~^
test01.cpp:26:26: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]26 |         compare("hello", "world");|                          ^~~~~~~|                          ||                          const char*
test01.cpp:23:33: note:   initializing argument 2 of ‘bool compare(int, int)23 |         bool compare(int a, int b);|                             ~~~~^

注意2:同一类型,加不加const在编译器眼中没有区别。

void func(int a) {}
void func(const int a) {}
// 报错void func(int *a) {}
void func(const int *a) {}
// 编译通过void func(int *a) {}
void func(int const *a) {}
// 报错

为什么 C++ 支持函数重载,C 语言不支持函数重载?

在对符号表中函数命名时,C++采取了更能准确描述一个函数的命名方式,而 C 语言直接用函数名字作为符号名。

因此,C 和 C++ 中的函数由于函数名不同,不能直接调用,会在链接时发生无法解析的外部符号的错误,因为在符号表中找不到对应的函数符号名。

要实现 C 和 C++ 之间都可以调用的函数,应该这样定义

#ifdef __cplusplus
extern "C" {
#endif
int sum(int a, int b) {return a + b;
}
#ifdef __cplusplus
}
#endif

掌握const的用法

基本理解:const 修饰的常变量不能作为左值使用。
常变量 != 常量,例如:

chipen@ubuntu:~/code/inlineTest$ cat test02.cpp 
#include <cstdio>int main() {const int a = 20;int *p = (int *)&a;*p = 30;printf("%d %d %d\n", a, *p, *(&a));return 0;        
}
chipen@ubuntu:~/code/inlineTest$ ./test02
20 30 30

这是个不可思议的现象。原因是:在编译器的前端阶段,a 被认为是不可能被修改的,故在后文中被做了直接替换,但是 *p, *(&a) 要求必须访问内存,故得到了 20 30 30。

证明这是一种优化行为:

chipen@ubuntu:~/code/inlineTest$ cat test02.cpp 
#include <cstdio>int main() {volatile const int a = 20;    # 不让编译器优化 aint *p = (int *)&a;*p = 30;printf("%d %d %d\n", a, *p, *(&a));return 0;        
}
chipen@ubuntu:~/code/inlineTest$ ./test02
30 30 30    # 符合预期

const修饰的量常出现的错误是:

  • 常量不能再作为左值 <= 直接修改常量的值
  • 不能把常量的地址泄露给一个普通的指针或者普通的引用变量 <= 可能间接修改常量的值

const和一级指针的结合:(const修饰的是离它最近的类型)

  • const int * p -> 指针指向的变量不能修改
  • int const * p -> 同上
  • int *const p -> 指针本身不能修改
  • const int *const p -> 指针本身和指针所指的变量都不能修改
int a = 10;            
int *p1 = &a;            // 通过, 无类型转换
const int *p2 = &a;        // 隐式类型转换
int *const p3 = &a;        // 隐式类型转换
const int b = 10;
int *p4 = &b;            // 不通过, (const int *) -> (int *)
const int *p5 = &b;        // 通过
int *const p6 = &b;        // 不通过, (const int *) -> (int *const)// 总结: 权限只能缩小不能扩大

const和二级/多级指针的结合

int a = 20;
int *p = &a;
const int **p1 = &p;
// 典型错误,这样赋值会让原来的普通指针 p 指向被 const 修饰的变量
/*
正确写法:
int a = 20;
const int *p = &a;
cosnt int **p1 = &p;
*/int *const *p2 = &p;
int **const p3 = &p;

左值引用和右值引用

int main() {int a = 10;    // 左值,有地址有名字,值可以修改int &b = a;int &&c = 20;    // 20 为右值,没内存,没名字c = 30// 右值引用可以修改const int &b = 20;/*int temp = 20;temp -> b*/const int &d = 20;return 0;
}

右值引用:

  • int &&c = 20;专门用来引用右值类型,指令上可以自动产生临时量,然后直接引用临时量。

  • 右值引用变量本身是一个左值,只能用左值引用来引用它。

  • 不能用一个右值引用变量引用一个左值。

const、指针和引用的结合应用

int main() {// 写一句代码,在内存的 0x0018ff44 处写一个 4 字节的 10int *p = (int *)0x0018ff44;int *&&p = (int *)0x0018ff44;int *const &p = (int *)0x0018ff44;return 0;
}

深入理解 c++ 的 new 和 delete

new 和 delete 为C++ 的运算符

malloc 和 free 为 C 的库函数

开辟内存失败时:

  • malloc 需要返回值与 nullptr 比较,为空时失败。

  • new 会抛异常。

new 有多少种?

int *p1 = new int(20);
int *p2 = new (nothrow) int;
int *p3 = new const int(40);// 定位 new
int data = 0;
int *p4 = new (&data) int(50);
cout << "data: " << data << endl;    // 输出 data: 0
http://www.dtcms.com/a/268979.html

相关文章:

  • GTA(传承/增强)1.71-3570环境补丁
  • 前端工程化设计详解
  • 摄影后期:使用Photoshop进行暗角控制
  • JavaSE -- 集合详细介绍(中篇)
  • 回溯题解——电话号码的字母组合【LeetCode】
  • C++ 虚函数(多态,多重继承,菱形继承)
  • Windows 7 环境下发布Python程序的 _socket 模块加载错误
  • jdk11安装详细教程window版和linux版
  • Node.js特训专栏-实战进阶:14.JWT令牌认证原理与实现
  • GitHub Actions自动化部署Vue项目到宝塔服务器
  • vue3+node.js+mysql写接口(一)
  • 【PTA数据结构 | C语言版】两枚硬币
  • SpringAI学习笔记-Chat简单示例
  • 无需科学网络,免费开源Pandawiki,无缝对接微信、飞书和钉钉!
  • Mac中Minicom串口调试基础使用
  • Redis架构安全
  • 基于Java+SpringBoot 的销售项目流程化管理系统
  • 利用英译法案例演示RNN中的注意力机制(基于PyTorch)
  • 通达信 股道交易系统 幅图
  • 汽车功能安全概念阶段开发【功能安全需求及方案(FSRFSC)】3
  • 风电自动化发电中的通信桥梁:CAN主站转MODBUS TCP网关解析
  • 基于Spring Boot和PF4J的轻量级热插拔框架:为FaaS赋能动态插件化开发
  • 单片机STM32F103如何实现CAN总线?
  • 第一届OpenHarmonyCTF--Crypto--WriteUp
  • 基于 STM32 和 ESP8266 的银行排队叫号系统设计与实现(项目资料)(ID:1)
  • 各服务器厂商调整BIOS睿频教程
  • Qt中的坐标系
  • QT的事件过滤器eventFilter
  • 【1】从零构建Vue3响应式系统:基于TDD的完整实现
  • 【kafka-python使用学习笔记2】Python操作Kafka之环境准备(2)亲测有效有图有真相