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 则表示全部主分片都正常运行(集群可以正常服务所有请求),但是 副本 分片没有全部处在正常状态. ...
随机推荐
- 使用调试工具调试博图TCP连接所遇到的问题
PLC端使用的指令 PLC为服务器端,电脑为客户端,以上为服务器与客户端的配置参数 启动连接后连接成功,PLC的IP地址也可以ping通 ------------------------------- ...
- C++子类的构造函数
子类的构造函数 子类可以有自己的构造函数 子类没有构造函数,默认系统会调用父类的构造函数 子类有自己的构造函数,系统会先运行父类的构造函数,随后运行子类的构造函数,对子类对象进行覆盖和拓展 即不论子类 ...
- DHorse v1.3.0 发布,基于k8s的发布平台
综述 DHorse是一个简单易用.以应用为中心的云原生DevOps系统,具有持续集成.持续部署.微服务治理等功能,无需安装依赖Docker.Maven.Node等环境即可发布Java.Vue.Reac ...
- 王道oj/problem17
网址:http:oj.lgwenda.com/problem17 思路:指针其实就是存储地址的一个空间,LinkList=LNode* 代码: #define _CRT_SECURE_NO_WARNI ...
- 快速掌握Vue3:速成Vue3前端开发看这篇就够啦
一.Vue基本概念 1.1-Vue3的优点 Vue3支持Vue2额大多数特性. 更好的支持TypeScript. 打包大小减少41%. 初次渲染快55%,更新渲染快133%. 内存减少54%. 使用p ...
- golang1.21新特性速览
经过了半年左右的开发,golang 1.21 在今天早上正式发布了. 这个版本中有不少重要的新特性和变更,尤其是在泛型相关的代码上. 因为有不少大变动,所以建议等第一个patch版本也就是1.21.1 ...
- JS自制极简日历Demo
这个日历界面不属于任何插件,纯粹用最基本的JS函数获取到每个位置对应的日期,然后再通过遍历拼接table表单的方式赋值到HTML里面进行展示,日历效果的显示,其中使用到的文件只需要一个Jquery的J ...
- Hugging News #0814: Llama 2 学习资源大汇总 🦙
每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...
- 【日常踩坑】修复 chrome 打不开微信或者部分第三方应用内链接
目录 默认浏览器为 chrome 时,打不开微信或者部分第三方应用内链接(或者没有反应) 修复问题:卸载 KGChromePlugin 参考资料 默认浏览器为 chrome 时,打不开微信或者部分第三 ...
- 以程序员的视角,介绍如何通过API接口获取淘宝商品数据的方法和步骤,并提供实际代码示例
当我们想要获取淘宝商品数据时,可以通过调用淘宝开放平台的API接口来实现.下面是一些步骤和示例代码来帮助你开始. 步骤1:申请开发者账号和应用 在开始之前,你需要在淘宝开放平台上注册一个开发者账号 ...