C++记录(二)
1.算术移位和逻辑移位。
逻辑移位是只补0,算术移位是看符号,负数补1,正数补0(讨论的是右移的情况下)。
负数左移右边一样补0。如果遇到位运算的相关题目需要对int变量进行左移而且不知道正负,那么先强制类型准换为unsigned再进行移位操作。
2.constexpr意义是字面值常量,即在编译期就可以将其计算出结果。
constexpr修饰函数名是高速编译器放心大胆的将该函数计算出结果(要满足形参和return的值都是常量才行)。
constexpr int f(int x)
{
return 6;
}
int main() {
int x = 1;
int p[f(x)]; //报错,因为形参x不是常量
int p[f(2)]; //成功
getchar();
return 0;
}
内联函数和constexpr函数定义都要放在头文件中,因为对这两种函数的优化都是在编译期做的,这个时候各个源文件之间还没有进行链接,如果放在某一个源文件里面(.cpp)
别的cpp根本就找不到这个函数的定义。 所有只有把函数定义放在头文件中,这样所有包含该函数的源文件都到该头文件中去才能找到该函数定义。
3.assert(x==4); //如果x等于4继续执行后面语句,否则跳出报错
在incude<assert.h>前面加#define NDEBUG 可以使assert失效,变为非debug模式。
4.类的复制构造函数如A(A other){pass},参数不能传值,因为传值会复制原对象为形参,这又需要调用复制构造函数,无限递归下去。
正确的方式是传引用。
5.类的成员函数参数列表后加const,相当于修饰的是对象的this指针。
举例:
class A
{
public:
void f ()const
{
cout<<"f:"<<x<<endl;
}
void g()
{
cout<<"g:"<<x<<endl;
}
A()=default;
private:
int x=1;
};
int main(int argc, char **argv)
{
A a;
const A b;
a.f();
a.g();
b.f();
b.g(); //这句会报错,常量调用非const方法,这样无法保证常量b的数据不被该方法篡改。
getchar();
return 0;
}
6.系统只要发现类里提供了构造函数,就不会再提供默认构造函数,所以写构造函数的话,一定把默认构造函数也加上。
7.一个const成员函数如果返回引用,该引用是常量引用,因为const成员函数的this指针是const A *const类型,
*this的类型是const A&(常量引用)。
8.类的友元函数是用来类之间数据通信的。类A的友元函数可以访问类B的private成员。
友元函数必须在类内声明,类外定义。
eg:
class Date;//对Date类的提前引用声明
class Time
{
public:
Time(int, int, int);//声明构造函数
void display(Date &); //display函数参数为date类型
private:
int hour;
int sec;
int minute;
};
class Date
{
public:
Date(int, int, int);//声明构造函数
friend void Time::display(Date &); //那么在date类里声明Time类的display函数为友元函数
private:
int mouth;
int day;
int year;
};
Time::Time(int h, int m, int s) //友元函数必须在类内声明,类外定义!!!!
{
hour = h;
minute = m;
sec = s;
}
9.指针作为函数参数,如果通过指针改变其指示位置存储的数据,是可以的。
但如果改变指针的指向,(指向另一块内存),从函数出去之后指针
仍然指向的是原来的区域。
原因:假设p为指针,函数f调用p,那么实际上会申请另一个指针p2=p,在函数
中将p2指向其他区域,是影响不到函数外指针p的指向的。而至于为什么可以改变p指向区域的数据,
是因为临时申请的指针p2指向的区域和p一样,故修改是可以成功的。
如果函数会修改指针的指向,那么要使用二级指针。
- ::是域作用符,下面代码会输出类A外面的a,而不是类的a。
int a=1;
class A
{
public:
int a=2;
void f()
{
cout<<::a;
}
};
int main()
{
A x;
x.f();
getchar();
}
11.const和引用变量必须初始化
类的成员变量如果有const或者引用类型的,如果不列表初始化或者直接在声明时就给定初始值,会报错!
类的列表初始化和正常的构造函数是有本质区别的!并且列表初始化比构造函数赋值要快,因为后者是先初始化再赋值。
12.如果一个类A有两个单参数的构造函数,那么这两个构造函数不可以都有默认实参,这样A x;会不知道调用哪个构造函数,即函数二义性。
普通函数不存在这个问题因为普通函数名不可能相同。
class A
{
int x;
int y;
public:
A(int a,int b):x(a),y(b){} //被委托的构造函数
A():A(0,0){} //委托最上面的构造函数进行构造
A(int a):A(a,0){} //委托最上面的构造函数进行构造
};
- default_random_engine只需要声明一次,随机数引擎每次初始化都是一个状态,会产生一模一样的随机数序列(所以应该叫伪随机数)。
uniform_int_distribution可以限制整形随机数的范围,uniform_real_distribution限制实数随机数的范围
eg:
int main()
{
default_random_engine e;
uniform_real_distribution<double> u(0,10000);
for(int i=0;i<1000000;++i)
{
cout<<u(e)<<endl;
}
15.
typedef int* p; //int*
typedef char q[5]; //长度5的char数组
typedef char *r[5]; //长度5的char*数组
typedef char (*s)[5]; //指向【长度为5的char数组】的指针
getline函数有两个,第一个声明如下,定义在fstream头文件里。
template<typename _CharT, typename _Traits, typename _Alloc>
inline basic_istream<_CharT, _Traits>&
getline(basic_istream<_CharT, _Traits>& __is,
basic_string<_CharT, _Traits, _Alloc>& __str)
{ return std::getline(__is, __str, __is.widen('\n')); }
该函数不是什么类的成员函数,所以调用时候直接getline(输入流,字符串)。第一个参数是输入流类,第二个参数是一个string引用。作用是从指定输入流读一行到string里保存。
另一个getline声明如下,定义在istream头文件里
__istream_type&
getline(char_type* __s, streamsize __n)
{ return this->getline(__s, __n, this->widen('\n')); }
然后往上翻它是属于basic_istream类的成员函数,所以调用格式是istream对象.getline(…)。
它的第一个参数是c字符串__s,第二个参数是字符串的长度__n。即从指定输入流读__n-1个字符到__s中,加’\0’结束。
template<typename _CharT, typename _Traits>
class basic_istream : virtual public basic_ios<_CharT, _Traits>
{
public:
stl的list模板迭代器只重载了++、–运算符,不能对list< int> ::iterator进行+=1这样的操作,迭代器也不可以互相比较大小。如有两个list::iterator迭代器l.begin()和l.end(),不可以写while(l.begin()<l.end())。其他顺序容器迭代器(如vector、deque、string等等)都是可以的,+=也是可以的。
begin(),end()
cbegin(),cend() //const_iterator版本
rbegin(),rend() //倒序版本
crbegin(),crend() //倒序const_iterator版本
18.emplace和insert函数的区别在于:当参数是一个类的实例时,emplace不必先构造临时变量再复制一个插入,它直接将数值传给相应容器的构造函数,只需要构造一次。insert要构造两次。其他emplace_back和emplace_front函数也一样。甚至emplace函数可以无形参调用,如下图
这样emplace_back会直接调用Bar的默认构造函数插入,但push_back函数不能没有形参,所以图中报错了。
double float等类型判等时不能直接用等于号,需要定义equal函数,判断两个量的值相减是否小于某个预设值(如1e-6)。
static_cast:只要不包含底层const,都可以用这个来强制转换。
const_cast:专门用来改变底层const
swap(stl1,stl2)可以交换两个同样类型的stl类型变量的内部数据。(速度很快,因为不会拷贝复制)
如:
vector<int> p1,p2;
swap(p1,p2);
list<int> l1,l2;
swap(l1,l2);
map<char,int> m1,m2;
swap(m1,m2);
- 线性stl容器(vector、list、forwar_list、string等)都有erase成员函数,一个是erase(iterator),一个是erase(iter1,iter2),其中iter2是删除的最后一个元素的下一个位置。这两个函数都返回最后删除元素的下一个位置的迭代器。
其中string除了上面两个共有的,还有一个单独的成员函数erase(pos,size),表示从pos索引开始删除size长度的子串,返回值是删除后的新字符串的引用。
共有insert成员函数,insert(iterator,num),将num插入到iterator前面,并返回新插入元素的迭代器。
静态成员函数只能操作静态成员变量。
静态成员变量在类内声明,类外定义。
静态成员函数可以在类内直接定义。函数指针
int F(int (*f)(int)){
(*f)(6);
}
int f(int x){
cout<<x*x<<endl;
return 0;
}
int main(){
F(f);
getchar();
}
- 不想某个类被拷贝,用=delete来定义复制构造函数和赋值运算符重载。
=delete可以用来定义任何函数,以表示该函数不能使用。
=default相当于空函数体,只能用来定义默认构造函数和复制构造函数!!
26. noexcept用来修饰程序员确定不会抛出异常的函数。因为普通的函数是有可能抛出异常的,编译器要对其设计一些额外代码,如果有了noexcept就可以省去这部分代码。
27. 输入输出符的重载都要作为友元函数,不能作为类的成员函数。另外输出函数不必考虑失败的情况,但输入函数如果存在计算再赋值的情况(如类里有价格、数量、总价),输入只输入价格和数量,总价由函数内部自行计算再赋值,那么就要考虑失败的情况,这时应该将类重新赋值为空。
28. 一般运算符重载作为非成员函数,比如string s; s="121"+s; 这里如果string的加法重载作为成员函数,那么就会报错,因为s="121"+s;相当于调用 "121".soperator+ (s);这显然不对。
operator+一般调用operator+=来实现,而不是反过来。这样可以节省一个临时变量的申请时间和空间。
29. 重载递增递减、下标运算符都要作为成员函数。其中前置++和后置++的区别是靠形参的不同来区别的,后置++的形参有一个int:
A& operator++(){
++feet,++inches;
return *this;
}
A operator++(int){
A temp=*this;
++feet,++inches;
return temp;
}
另外前置++返回引用,后置++返回右值不用多说了。
可以看到,STL也是这么干的:
C++记录(二)的更多相关文章
- Material Calendar View 学习记录(二)
Material Calendar View 学习记录(二) github link: material-calendarview; 在学习记录一中简单翻译了该开源项目的README.md文档.接下来 ...
- Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客
==他的博客应该不错,没有细看 Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客 http://blog.csdn.net/u012706811/article/det ...
- 前端常用功能记录(二)—datatables表格(转)
前端常用功能记录(二)—datatables表格 并不是所有的后台开发都有美工和前端工程师来配合做页面,为了显示数据并有一定的美感,jQuery的DataTables插件对于像我这样的前端菜鸟来说真是 ...
- JavaScript学习记录二
title: JavaScript学习记录二 toc: true date: 2018-09-13 10:14:53 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...
- 2.VUE前端框架学习记录二
VUE前端框架学习记录二:Vue核心基础2(完结)文字信息没办法描述清楚,主要看编码实战里面,有附带有一个完整可用的Html页面,有需要的同学到脑图里面自取.脑图地址http://naotu.baid ...
- 面试问题记录 二 (数据库、Linux、Redis)
面试问题记录 二 (数据库.Linux.Redis) 前言 接着上次的面试问题记录,在最后还有几道问的数据结构方面的知识点要补充 还是那句话:如果文中解释有明显错误,劳烦请及时指正我,在这不胜感激!! ...
- Lucene.net(4.8.0) 学习问题记录二: 分词器Analyzer中的TokenStream和AttributeSource
前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3 ...
- 前端常用功能记录(二)—datatables表格
并不是所有的后台开发都有美工和前端工程师来配合做页面,为了显示数据并有一定的美感,jQuery的DataTables插件对于像我这样的前端菜鸟来说真是雪中送炭,当然对于专业的前端开发者来说它更是锦上添 ...
- SpringBoot学习记录(二)
一. SpringBoot日志框架 SpringBoot:底层是Spring框架,Spring框架默认是用JCL(commons-logging): SpringBoot选用SLF4j和logback ...
- grpc使用记录(二)简单同步服务实例
目录 1.编写proto文件,定义服务 2.编译proto文件,生成代码 3.编写服务端代码 server.cpp 代码 编译 4.编写客户端代码 client.cpp代码 5.简单测试一下 已经折腾 ...
随机推荐
- Spark应用开发调优要点总结
调试Spark应用性能的时候,首先应该理解spark是如何工作以及你的spark应用需要何种类型的资源.比如说,机器学习相关的spark应用更依赖cpu计算能力,ETL应用更依赖I/O能力,以此进行有 ...
- .net平台 通过Windows installer 打包和部署实例操作
Windows installer 打包和部署 1.新建项目. 打开VS,新建项目->其他项目类型->安装和部署(Visual Studio Installer). 注:若VS2013 或 ...
- input禁止输入的方法
1: readonly规定输入字段为只读可复制,但是,用户可以使用Tab键切换到该字段,可选择,可以接收焦点,还可以选中或拷贝其文本. <input type="text" ...
- 小程序上拉触底&下拉加载
data: { pageNo: 1,//当前页 pageSize: 10,//每页条数 count:'',//总条数 orderList: [], }, onLoad: function () { v ...
- pyqt5加载pdf文档失败
import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog from PyPDF2 import Pdf ...
- js遇到代码出现问题时如何调试代码
单步跟踪调试 debugger; 控制台watch功能查看变量当前值 进入函数操作 随着不断点击,不停进行循环,指定变量的值也在发生改变 添加断点 跳入跳出函数 throw new Error() 主 ...
- CF594D REQ [离线+树状数组,欧拉函数]
设 \[x = \prod_{i=1}^{cnt} p_i^{k_i} [p_i\in prime]\] 那么显然 \[\varphi(x) = x*\frac{1} {\prod_{i=1}^{cn ...
- JS实现登录页密码的显示和隐藏功能
在登录页经常会用到通过点击文本框的类似小眼睛图片来实现隐藏显示密码的功能,其实实现原理很简单,通过点击事件来改变input的type类型,具体过程看代码: 在没给大家分享实现代码之前,先给大家展示下效 ...
- 复习mongoose的基本使用
mongodb参考 mongoose官网 mongoose用起来更便捷,更方便些
- linux 文件系统管理三部曲之三:挂载文件系统
linux 文件系统管理三部曲之一:磁盘分区 linux 文件系统管理三部曲之二:创建文件系统 上面说明了,硬盘的划分和格式化,那么怎么使用,还没说,这里说一下,怎么使用创建好的文件系统. 使用文件系 ...