Override 关键字:
明确的表示一个函数是对基类中一个虚函数的重载。
class G
{
public:
virtualvoid func(int);
};
class H: G
{
public:
virtualvoid func(double) override; //compilation error
};
当处理到H::func()声明时,编译器会 在一个基类查找与之匹配的虚函数。
final函数和类:
C++11有两个用途,第一阻止从类继承,第二阻止一个虚函数的重载。
无子类类型:
classTaskManager
{
/*..*/
} final;
classPrioritizedTaskManager: publicTaskManager
{
}; //compilationerror: base classTaskManagerisfinal
禁止虚函数被进一步重载:
classA
{
pulic:
virtual void func() const;
};
class B: A
{
pulic:
void func() constoverridefinal; //OK
};
classC:B
{
pulic:
void func()const; //error, B::func is final
};
C++11之右值引用:
左值是指表达式结束后依然存在的持久对象,右值是指表达式结束时就不再存在的临时对象,一个区分左值右值的便捷方法是:看能不能对表达式取地址,如果能,就是左值,否则为右值。
右值一般指的是表达式中的临时变量,在C++中临时
变量在表达式结束后就被销毁了,之后程序就无法再引用这个变量了,C++11提供了一个方法,让我们可以引用这个临时变量,这个方法就是所谓右值引用。
那么右值引用有什么用呢?避免内存copy!因此对于赋值操作意味着内存拷贝而不是简单的赋值指针。而右值引用的一个作用就是我们可以通过重新利用临时变量(右值)来避免无意义的内存copy。
右值引用的符号:“&&”
int a = 0;
a是一个左值,左值是一个变量,可以被引用和多次使用。0是一个右值,不可以被引用。左值一般是非临时变量,可以被多次使用。右值只在当前表达式有效。
classMyClassB
{
public:
void init(int & intval)
{ cout<<"use & print"<<endl;};
void init(int &&intval)
{ cout<<"use && print"<<endl;}
};
intmain(void)
{
int ae = 10;
MyClassB().init(10);
MyClassB().init(ae);
return0;
}
右值引用是用来支持转移语义,转移语义可以将资源从一个对象转移到另一个对象,这样可以减少不必要的临时对象的创建,拷贝及销毁,大幅度提高C++应用程序的性能。
浅拷贝与move语义的区别在于,浅拷贝是共享资源,而move是独占资源,浅拷贝因共享资源从而可能引发重复析构的问题,而move是独占则不会。
标准库函数 std::move
以非常简单的方式将左值引用转换为右值引用。
IBM Developer 正在整合其语言站点组合。 – IBM Developer
我们先定义转移构造函数。
MyString(MyString&& str) {
std::cout << "Move Constructoris called! source: " << str._data << std::endl;
_len = str._len;
_data = str._data;
str._len = 0;
str._data = NULL;
}
和拷贝构造函数类似,有几点需要注意:
1. 参数(右值)的符号必须是右值引用符号,即“&&”。
2. 参数(右值)不可以是常量,因为我们需要修改右值。
3. 参数(右值)的资源链接和标记必须修改。否则,右值的析构函数就会释放资源。转移到新对象的资源也就无效了。
示例程序 :
void ProcessValue(int& i) {
std::cout << "LValue processed: " << i << std::endl;
}
void ProcessValue(int&& i) {
std::cout << "RValue processed: " << i << std::endl;
}
int main() {
int a = 0;
ProcessValue(a);
ProcessValue(std::move(a));
}
运行结果 :
LValue processed: 0
RValue processed: 0
精确传递(Perfect Forwarding)
Lambda表达式解析:
Lambda表达式是右值引用。
方便的构造匿名函数,如果代码存在大量小函数,而这些函数一般只被调用一次,不妨将他们重构成lambda表达式。
[ capture ] ( params ) mutable exception attribute -> ret { body } | (1) |
|
[ capture ] ( params ) -> ret { body } | (2) |
|
[ capture ] ( params ) { body } | (3) |
|
[ capture ] { body } | (4) |
|
其中
· (1) 是完整的 lambda表达式形式,
· (2) const 类型的 lambda表达式,该类型的表达式不能改捕获("capture")列表中的值。
· (3)省略了返回值类型的 lambda表达式,但是该 lambda 表达式的返回类型可以按照下列规则推演出来:
· 如果 lambda代码块中包含了 return 语句,则该 lambda 表达式的返回类型由 return语句的返回类型确定。
· 如果没有 return语句,则类似 void f(...) 函数。
· 省略了参数列表,类似于无参函数 f()。
mutable 修饰符说明 lambda 表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获对象的 non-const 方法。
exception 说明 lambda 表达式是否抛出异常(noexcept),以及抛出何种异常,类似于void f() throw(X,Y)。
attribute 用来声明属性。
另外,capture 指定了在可见域范围内 lambda 表达式的代码内可见得外部变量的列表,具体解释如下:
· [a,&b] a变量以值的方式呗捕获,b以引用的方式被捕获。
· [this] 以值的方式捕获 this 指针。
· [&] 以引用的方式捕获所有的外部自动变量。
· [=] 以值的方式捕获所有的外部自动变量。
· [] 不捕获外部的任何变量。
此外,params 指定 lambda表达式的参数。
————————————————————————————
Char和String之间的转换
C++中char类型可以自动转换成string类型,即你可以用char类型字符串直接给string类型变量赋值。但反过来是不行的,string类型不能隐式的将string类型转换成char类型,想要转换,必须显式调用c_str()函数。给你举个例子:
string s1;
const char *pc = "a character array";
s1 = pc; // ok
char *str = s1; // 编译时刻类型错误
const char *str = s1.c_str(); // ok
————————————————————
explicit构造函数的作用
解析:
explicit构造函数是用来防止隐式转换的。请看下面的代码:
class Test1
{
public:
Test1(int n)
{
num=n;
}//普通构造函数
private:
int num;
};
class Test2
{
public:
explicit Test2(int n)
{
num=n;
}//explicit(显式)构造函数
private:
int num;
};
int main()
{
Test1 t1=12;//隐式调用其构造函数,成功
Test2 t2=12;//编译错误,不能隐式调用其构造函数
Test2 t2(12);//显式调用成功
return 0;
}
普通构造函数能够被隐式调用。而explicit构造函数只能被显式调用。Test1的构造函数带一个int型的参数,代码23行会隐式转换成调用Test1的这个构造函数。而Test2的构造函数被声明为explicit(显式),这表示不能通过隐式转换来调用这个构造函数,因此代码24行会出现编译错误。
————————————————————————
std::ifstream的使用方法和作用
ifstream 已有的文件读
————————————————————————
Decltype
https://www.devbean.net/2012/05/cpp11-decltype/
decltype
类型说明符生成指定表达式的类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。
int var;
const int &&fx();
struct A { doublex; }
const A* a = new A();
语句 | 类型 | 注释 |
decltype(fx()); | const int && | 对左值引用的const int |
decltype(var); | int | 变量 var 的类型 |
decltype(a->x); | double | 成员访问的类型 |
decltype((a->x)); | const double& | 内部括号导致语句作为表达式而不是成员访问计算。由于a声明为 const指针,因此类型是对const double的引用。 |
——————————————————
Delete和default
http://blog.csdn.net/u012333003/article/details/25299939
1. class LeafFromTree{
2. public:
3. LeafFromTree() = default;
4. ~LeafFromTree() = default;
5.
6. LeafFromTree( const LeafFromTree& ) = delete; // mark copy ctor or copy assignment operator as deleted functions
7. LeafFromTree & operator=( const LeafFromTree &) = delete;
8. };
9. 在函数重载中,可用 delete 来滤掉一些函数的形参类型,如下:
10.bool isLucky(int number); // original function
11.bool isLucky(char) = delete; // reject chars
12.bool isLucky(bool) = delete; // reject bools
13.bool isLucky(double) = delete; // reject doubles and floats
14. 这样在调用 isLucky 函数时,如果参数类型不对,则会出现错误提示
15.if (isLucky('a')) … // error ! call to deleted function
16.if (isLucky(true)) … // error !
17.if (isLucky(3.5)) … // error !
C++11 中,可在想要 “禁止使用” 的函数声明后加“= delete”,而需要保留的加"= default" 或者不采取操作
Constexpr
运行效率方面:unordered_map最高,而map效率较低但提供了稳定效率和有序的序列。
占用内存方面:map内存占用略低,unordered_map内存占用略高,而且是线性成比例的。
需要无序容器,快速查找删除,不担心略高的内存时用unordered_map;有序容器稳定查找删除效率,内存很在意时候用map。
Tuple(元组)
tuple是一个固定大小的不同类型值的集合,是泛化的std::pair。和c#中的tuple类似,但是比c#中的tuple强大得多。我们也可以把他当做一个通用的结构体来用,不需要创建结构体又获取结构体的特征,在某些情况下可以取代结构体使程序更简洁,直观。
创建右值的引用元组方法:forward_as_tuple。
std::map<int, std::string> m;
m.emplace(std::piecewise_construct,
std::forward_as_tuple(10),
std::forward_as_tuple(20, 'a'));
std::cout << "m[10] = " << m[10] << '\n';
output : m[10] = aaaaaaaaaaaaaaaaaaaa
它实际上创建了一个类似于std::tuple<int&&,std::string&&>类型的tuple。