C++基础杂记(2)
- 将数组传入函数
- 函数的地址与函数的指针
- 函数的 static 与 inline
- 引用左值和引用传参
- C++11 的数组 for 循环
- 64 位 Linux 操作系统中 C++ 中常见基本类型所占字节数
- C++11 类成员变量的初始化
- 友元可以访问类的私有变量
将数组传入函数
void test(int array[]);
void test(int* array);
两种传递方式完全等价,但是第一种传递方式的可读性更高。
禁止修改数组的值
void test(const int array[]);
void test(const int* array);
注意,const 能用则用,如果声明函数时。函数的参数是带 const 的,则函数可以接受带 const 或不带 const 的参数。若函数参数不带 const,则只能接受不带 const 的参数。
函数的地址与函数的指针
#include <iostream>
using namespace std;
void myPrint()
{
cout<< "myPrint\n";
return;
}
void getResult(void (*printMethod)(void)) // 函数的参数为函数指针/地址
{
(*printMethod)(); // printMethod(); 同样有效
return;
}
int main(int argc, char** argv)
{
void (*myPrintPtr)(void); // 函数指针
myPrintPtr = myPrint; // 将函数地址赋值给函数指针
cout<< "myPrint 函数地址:"<< (void*)myPrint<< endl; // 由于cout没有输出函数地址类型的重载,因此需要显示的将函数地址声明为指针类型才能有效输出。否则会默认输出boolean值
cout<< "myPrint 函数指针:"<< (void*)myPrintPtr<< endl; // 由于cout没有输出函数指针类型的重载,因此需要显示的将函数指针声明为指针类型才能有效输出。否则会默认输出boolean值
cout<< "myPrint 函数指针地址:"<< &myPrintPtr<< endl;
getResult(myPrint); // 可以接受函数地址
getResult(myPrintPtr); // 可以接受函数指针
return 0;
}
myPrint 函数地址:0x55b39f80097a
myPrint 函数指针:0x55b39f80097a
myPrint 函数指针地址:0x7ffd48cd26b0
myPrint
myPrint
注意,下列示例中,直接将函数声明为指针是不合法的:
void (*myPrint)()
{
cout<< "myPrint\n";
return;
}
函数的指针只是一个指针,不能像函数一样链接代码块。
函数的指针数组
void (*ptr[3])(void) = {func1, func2, func3}; // 定义一个包含三个函数地址的函数指针数组
上述代码可以使用 typedef 简化:
typedef void(*void_ptr)(void);
void_ptr pa[3] = {func1, func2, func3};
函数的 static 与 inline
- static 静态函数。限制函数的作用域为本文件,不能够被其他文件调用
- inline 内联函数。建议编译器将函数体嵌入调用他的地方,类似于宏定义的替换。这样可以使得函数在被调用时,程序不需要跳转到函数处,可以提高效率,但占用内存。inline 修饰的函数不能够先声明后定义,只能够直接进行定义。
引用左值和引用传参
- 当将临时变量赋给引用时,该引用需要被const修饰
double a = 10.0;
const int & b = (int)a; // (int)a 产生临时变量,一般来讲,右值表达式都将产生临时常量。临时常量无法被寻址,在左值处加入 const 修饰会让编译器创建一个无名常量记录临时常量的信息,该无名常量可以被寻址,但不可以被改变。
- 以普通引用作为形参的函数不能接收常量作为实参传递
#include <iostream>
using namespace std;
void test(int & a);
int main()
{
const int a = 10; // 常量
test(a); // 将常量传递给普通引用函数
return 0;
}
void test(int & a)
{
cout<< a<< endl;
}
报错:test.cpp:10:8: error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
- 当函数以常量引用作为形参时,可以接受非常量传参
- 更多细节参考文章
C++11 的数组 for 循环
int a[] = {1, 2, 3, 4};
for(int b:a)
{
cout<< b<< " ";
++b;
}
cout<< endl;
for(int b:a)
{
cout<< b<< " ";
}
cout<< endl;
1 2 3 4
1 2 3 4
这里第一个for循环中的数组a中的每一个值相当于按值传递给b,b的地址是唯一的且不指向a数组中的值。修改b无法修改a数组。
int a[] = {1, 2, 3, 4};
for(int & b:a)
{
cout<< b<< " ";
++b;
}
cout<< endl;
for(int b:a)
{
cout<< b<< " ";
}
cout<< endl;
1 2 3 4
2 3 4 5
想要修改a数组,则需要在第一个for循环中,让a数组中的值传引用到b,此时b指向a数组中的值,修改b可以修改a数组。
64 位 Linux 操作系统中 C++ 中常见基本类型所占字节数
pointer: 8字节
char : 1字节
unsigned char : 1字节
char16_t : 2字节
short : 2字节
unsigned short : 2字节
char32_t : 4字节
w_char : 4字节
int : 4字节
unsigned int : 4字节
float : 4字节
long : 8字节
long long : 8字节
unsigned long (long) : 8字节
double : 8字节
long double : 16字节
字节数比指针大的,声明函数时按参传递会有优势。
C++11 类成员变量的初始化
默认成员初始化器
在声明变量时直接初始化
class Baby
{
public:
Baby(const std::string name) : _name_(name) {}
Baby(int age) : _age_(age) {}
private:
// 默认成员初始化, 在声明处就进行初始化。
std::string _name_ = "Unknown";
int _age_ = 0;
int _weight_ = 0;
int _height_ = 0;
};
成员变量初始化列表
class Baby
{
public:
// 采取成员初始化列表方式,大量成员变量在多个初始化列表中重复出现
Baby(const std::string name):_name_(name), _age_(0), _weight_(0), _height_(0){}
Baby(int age) :_name_("Unknown"), _age_(age), _weight_(0), _height_(0) {}
// ...省略100个构造函数
// 采取先默认构造,再在构造函数中赋值,有机会去除这类重复代码。
Baby(const std::string name){
init(name, 0, 0, 0);
}
Baby(int age){
init("Unknown", age, 0, 0);
}
// ...省略100个构造函数
void init(const std::string& name, int age, int weight, int height)
{
_name_ = name;
_age_ = age;
_weight_ = weight;
_height_ = height;
}
private:
std::string _name_;
int _age_;
int _weight_;
int _height_;
};
传统的,在构造函数函数体里面进行初始化,实际上是先将变量初始化为0再赋值。而列表初始化,是直接在为变量分配内存时就初始化为对应的值。效率更高。
委托构造函数
如果构造函数需要更多的重构,写起来会很麻烦,C++11 允许我们将这些重构委托给一个构造函数
class Baby
{
public:
Baby(const std::string& name, int age, int weight, int height) :
_name_(name), _age_(age), _weight_(weight), _height_(height) {}
Baby(const std::string name) : Baby(name, 0, 0, 0) {} // 委托构造函数方式
Baby(int age) : Baby("Unknown", age, 0, 0) {} // 委托构造函数方式
// ...省略100个构造函数
private:
std::string _name_;
int _age_;
int _weight_;
int _height_;
};
定义对象时使用列表初始化
在 C++11 中,类可以如同结构体一般,在定义对象时使用列表进行初始化。前提是我们的构造函数中有相对应的方法。
class Baby
{
public:
Baby(const std::string& name, int age, int weight, int height) :
_name_(name), _age_(age), _weight_(weight), _height_(height) {}
private:
std::string _name_;
int _age_;
int _weight_;
int _height_;
};
int main()
{
Baby baby = {"name", 10, 10, 10}; // 复制列表初始化
Baby baby {"name", 10, 10, 10}; // 列表初始化
}
当构造函数没有被 explicit 修饰时,复制列表初始化与列表初始化都是合法的,但是当构造函数被 explicit 修饰时,被修饰的构造函数的类,不能发生相应的隐式类型转换,此时最好使用列表初始化而不使用复制列表初始化。
另外,类中成员变量的初始化顺序取决于他们在类中被声明的顺序。
友元可以访问类的私有变量
class Baby
{
private:
std::string baby_name;
int baby_age;
double baby_weight;
public:
Baby(const std::string & _baby_name, const int _baby_age, const double _baby_weight):baby_name(_baby_name), baby_age(_baby_age), baby_weight(_baby_weight){}
inline void showName() const {std::cout<<"Name: "<<baby_name<<std::endl;}
inline void showAge() const {std::cout<<"Age: "<< baby_age<<std::endl;}
inline void showWeight() const {std::cout<<"Weight: "<<baby_weight<<std::endl;}
inline void showAll() const {showName();showAge();showWeight();}
friend std::ostream & operator<<(std::ostream & os, const Baby & baby); // 友元声明
};
std::ostream & operator<<(std::ostream & os, const Baby & baby) // 友元定义
{
os<<"Name: " <<baby.baby_name <<std::endl // 友元使用了私有变量
<<"Age: " <<baby.baby_age <<std::endl // 友元使用了私有变量
<<"Weight: " <<baby.baby_weight <<std::endl; // 友元使用了私有变量
return os;
}
int main()
{
Baby baby = {"name", 2, 15};
baby.showAll(); // 打印全部信息
std::cout<<baby; // 打印全部信息
return 0;
}
示例中,类可以通过他自己的公共方法 showAll 来打印信息,也可以通过友元重载 << 运算符来打印信息。在友元的定义中,我们访问了类的私有变量。友元可以访问类的私有变量。
C++基础杂记(2)的更多相关文章
- java复习(2)---java基础杂记
java命名规范: 参考:http://www.cnblogs.com/maowang1991/archive/2013/06/29/3162366.html 1.项目名小写 2.包名小写 3.类名每 ...
- Webpack系列-第一篇基础杂记
前言 公司的前端项目基本都是用Webpack来做工程化的,而Webpack虽然只是一个工具,但内部涉及到非常多的知识,之前一直靠CV来解决问题,之知其然不知其所以然,希望这次能整理一下相关的知识点. ...
- python基础杂记
一.编码 1.ACSII 0000 0001 8位 一个字节 2. uncoide ...
- .Net基础杂记
1.面向对象程序思想 面向对象是程序开发的一种机制,特征为封装.继承.多态.以面向对象方式编写程序时,将复杂的项目抽象为多个对象互相协作的模型,然后编写模型结构,声明或实现类型的成员,即描述对象的特征 ...
- Webpack系列-第三篇流程杂记
系列文章 Webpack系列-第一篇基础杂记 Webpack系列-第二篇插件机制杂记 Webpack系列-第三篇流程杂记 前言 本文章个人理解, 只是为了理清webpack流程, 没有关注内部过多细节 ...
- webpack-插件机制杂记
系列文章 Webpack系列-第一篇基础杂记 webpack系列-插件机制杂记 前言 webpack本身并不难,他所完成的各种复杂炫酷的功能都依赖于他的插件机制.或许我们在日常的开发需求中并不需要自己 ...
- 5天揭秘js高级技术-第一天
一.基础杂记 1. document.write() <script type="text/javascript"> document.write('<h2> ...
- 面试基础知识集合(python、计算机网络、操作系统、数据结构、数据库等杂记)
python python _.__.__xx__之间的差别 python中range.xrange和randrange的区别 python中 =.copy.deepcopy的差别 python 继承 ...
- java基础(杂记)
java基础夯实(杂记):1:创建实例对象可以通过无参的构造函数然后调用成员变量去初始化属性,也可以自己定义有参构造方法直接初始化属性,当属性为private时我们可以通过getset方法间接访问:2 ...
- elasticsearch基础知识杂记
日常工作中用到的ES相关基础知识和总结.不足之处请指正,会持续更新. 1.集群的健康状况为 yellow 则表示全部主分片都正常运行(集群可以正常服务所有请求),但是 副本 分片没有全部处在正常状态. ...
随机推荐
- Python数据分析易错知识点归纳(三):Pandas
三.pandas 不带括号的基本属性 df.index # 结果是一个Index对象, 可以使用等号重新赋值,如: df.index = ['a', 'b', 'c'] df.columns # 结果 ...
- 利用shell脚本交互式运行jar任务
如题,废话不多说,直接上代码: #!/bin/bash APP_PATH=/root/bigdata/neural_networks/width_control_model/predict/uploa ...
- [jmeter]简介与安装
简介 JMeter是开源软件Apache基金会下的一个性能测试工具,用来测试部署在服务器端的应用程序的性能. 安装 安装jmeter 从 官网 下载jmeter的压缩包 安装jdk并配置 JAVA_H ...
- 使用CoreDNS自建dns
前言 公司有些内网服务需要使用域名访问,安装bind比较麻烦,故使用coredns实现域名服务. IP 说明 192.168.0.41 安装dns,作为dns服务器 192.168.0.20 测试服务 ...
- quarkus依赖注入之十一:拦截器高级特性上篇(属性设置和重复使用)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<quarkus依赖注入> ...
- Vue【原创】时间轴 【time-axis】&【date-axis】
封装了关于时间轴的组件,有时候统计页面会用到. 效果图: 时间轴分为2种,一种是time-axis:范围选择模式,一种是date-axis:步长选择模式. 代码中涉及到的工具类和图片资源,请移步页面底 ...
- 国内镜像安装Python解释器及扩展包
一.下载Python解释器 1.下载地址 官网(下载速度很慢):Welcome to Python.org 淘宝镜像(推荐):CNPM Binaries Mirror (npmmirror.com) ...
- 正则表达式快速入门一:正则表达式(regex)基本语法及概念
Regex quickstart :正则表达式快速入门 author: wclsn reference quick start 如果想要了解正则表达式的基本概念且英文ok的话,完全可以从我上面所附网站 ...
- 搭一下 Stable Diffusion WebUI
Preface 前不久看到好多朋友用上Stable Diffusion来做原画,然后又配合上了Chatgpt. 一直以来都想尝试一下,奈何2014款的双核mac跑个idea都发出了拖拉机的轰鸣声. 所 ...
- 别再用 float 布局了,flex 才是未来!
大家好,我是树哥! 前面一篇文章整体介绍了 CSS 的布局知识,其中说到 float 布局是 CSS 不断完善的副产物.而在 2023 年的今天,flex 这种布局方式才是未来!那么今天我们就来学习下 ...