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.简单测试一下 已经折腾 ...
随机推荐
- 微软帮助类SqlHelper
using System; using System.Data; using System.Xml; using System.Data.SqlClient; using System.Collect ...
- MAC使用命令行解压rar
使用homebrew安装unrar brew install unrar 安装完成后cd到rar文件目录,使用终端命令解压 unrar x 需要解压的文件
- C++\CLI使用.net委托,*Callback注意"this"
今天在使用c++\cli的时候遇到了点关于委托,callback使用的问题,简单记录一下 首先贴段简单的C#中使用System.Threading.Timer的代码. Timer GameTim ...
- 一键安装最新内核并开启 BBR 脚本
最近,Google 开源了其 TCP BBR 拥塞控制算法,并提交到了 Linux 内核,从 4.9 开始,Linux 内核已经用上了该算法.根据以往的传统,Google 总是先在自家的生产环境上线运 ...
- webpack4从安装到使用入过的那些坑
1.全局安装 安装 webpack 前要确保已经下载 node.js 最新版本(node.js官网地址) 目前使用命令行安装的 webpack 默认为最新版本(以下我使用了全局安装.官网建议本地安装, ...
- 用idea打包maven项目
利用idea工具打包项目 1.点击图中标记①,idea会自动生成打包命令,这个打包命令会包含单元测试内容,如果单元测试的内容报错,是打包不成功的,这个时候我们需要在打包命令中用 -Dmaven.tes ...
- C#调用Crypto++库AES ECB CBC加解密
本文章使用上一篇<C#调用C++类库例子>的项目代码作为Demo.本文中,C#将调用C++的Crypto++库,实现AES的ECB和CBC加解密. 一.下载Crypto 1.进入Crypt ...
- Miller-Rabin素数检测算法 acm模板
Miller-Rabin素数检测算法 其基于以下两个定理. Fermat小定理 若n是素数,则∀a(a̸≡0(modn))\forall a(a \not\equiv 0 \pmod{n})∀a(a̸ ...
- Object的对象的相关方法
Object.getPrototypeOf() Object.getPrototypeOf方法返回参数对象的原型.这是获取原型对象的标准方法. var F = function () {}; var ...
- JavaScirpt 认识DOM和BOM (汇总)
将HTML代码分解为DOM节点层次图 DOM节点有: 1. 元素节点:上图中<html>.<body>.<p>等都是元素节点,即标签. 2. 文本节点:向用户展示的 ...