今天主要说的事C++11中的在实际开发中很少用到的特性,这些特性虽然很少用,但是使用之后又让人眼前一亮,心生佩服。比如通过委托构造函数和集成构造函数可以少写很多不必要的函数,使用final和override可以增强代码的可读性且可以避免很多低级错误等等。
1 委托构造函数和集成构造函数
1.1 委托构造函数
委托构造函数云讯在同一个勒种一个构造函数可以调用 另外一个构造函数,代码如下:
class GetNumber{
public:
GetNumber(int iMax):max(iMax){}
GetNumber(int iMax,int iMin):GetNumber(iMax)
{
min = iMin >0 && iMin<iMax? iMin:1;
}
GetNumber(int iMax,int iMin,int iMiddle):GetNumber(iMax,iMin)
{
middle = iMiddle > iMin && iMiddle < iMax ? iMiddle:2;
}
private:
int max;
int min;
int middle;
};
委托构造函数需要注意的是,如果使用了代理构造函数就不能使用类成员函数初始化,而要使用变量赋值的方法。
1.1 继承构造函数
C++11中,允许派生函数使用基类的构造函数,这样可以极大简化构造函数的编写,尤其是在基类成构造函数较多的情况下。使用方法如下:
class Base{
public:
Base(int iMax):max(iMax){};
Base(int iMax,int iMin):max(iMax),min(iMin)
{
}
Base(int iMax,int iMin,int iMiddle):max(iMax),min(iMin),middle(iMiddle)
{
}
private:
int max;
int min;
int middle;
};
class Derived:Base{
using Base::Base;
};
int main ()
{
Derived d(1);
return 0;
}
从上面代码中可以看到,在派生类中使用using语句后派生类可以减少很多构造函数的编写。
2 原始的字面量
编码时如果遇到需要传入文件路径时,一般要加上转义符,才能正确表示一个文件路径,C++11后,新增了原始字符串字面量“R”,原始字面量的使用不需要我们对字符串进行特殊处理,输出时就会输出字符串原始的含义。使用方法为:
int main ()
{
std::string str = R"test(d:\A\B\test.bat)test";
std::cout<<str;
return 0;
}
上面的代码如果通过编译器进行输出的话输出内容为:
d:\A\B\test.bat
使用时需要注意的点是:
3 final和override
和java语言类似,final标识符表示类不能被继,或者虚函数不能被重写,写法如下:
class A
{
virtual void Add() final;
};
如果在非虚函数上加final,则编译会报错,如:
class A
{
void Add() final;//编译报错
};
报错信息如下:
error: 'void A::Add()' marked final, but is not virtual
同理,如果类被定义成了final:
class A final
{
void Add();
};
class B:A
{
};
报错信息如下:
error: cannot derive from 'final' base 'A' in derived type 'B'
override标识符可以提高代码的可读性,避免因为失误导致的本来要重写的虚函数变成重载。使用方法如下:
class A
{
virtual void Add();
};
class B:A
{
void Add() override
{
}
};
4 C++ 11 中新增的便利算法
C++ 11中新增了一些便利的算法,使用后,代码将会变得更加简洁、方便。
4.1 all_of,any_of,none_of
三个算法的原型为:
template <class InputIterator, class UnaryPredicate>
bool all_of (InputIterator first, InputIterator last, UnaryPredicate pred);
template <class InputIterator, class UnaryPredicate>
bool any_of (InputIterator first, InputIterator last, UnaryPredicate pred);
template <class InputIterator, class UnaryPredicate>
bool none_of (InputIterator first, InputIterator last, UnaryPredicate pred);
这三个算法均对一个检查区间进行查找,查找条件满足一个一元判断式。如果有一个元素满足条件,则返回true,否则返回false。代码如下:
int main () {
std::array<int,8> foo = {1,2,4,8,16,32,64,128};
if ( std::none_of(foo.begin(), foo.end(), [](int i){return i<0;}) )
std::cout << "所有的数都不小于0.\n";
if ( std::all_of(foo.begin(), foo.end(), [](int i){return i%2 == 0;}) )
std::cout << "所有的数都是偶数.\n";
if ( std::any_of(foo.begin(), foo.end(), [](int i){return i%2 == 1;}) )
std::cout << "至少有一个数是奇数.\n";
return 0;
}
代码运行结果为:
所有的数都不小于0.
至少有一个数是奇数.
4.2 find_if_not 、find_if算法
该算法的功能和find_if相反,虽然通过彼此都可以相互实现,但是为了编码时不用再写否定判断式提升代码可读性,还是新增了单独的算法进行实现,代码使用方法如下:
int main () {
std::array<int,5> foo = {1,2,3,4,5};
std::array<int,5>::iterator it =
std::find_if_not (foo.begin(), foo.end(), [](int i){return i%2;} );
std::cout << "The first even value is " << *it << '\n';
std::array<int,5>::iterator it1 =
std::find_if (foo.begin(), foo.end(), [](int i){return i%2==0;} );
std::cout << "The first even value is " << *it1 << '\n';
return 0;
}
如上代码所示,输出结果是一样,都是:The first even value is 2
4.3 copy_if 算法
通copy算法一样,都是拷贝一段区间内的值,但是copy_if增加了一个条件,只有满足条件的才会进行拷贝,copy_if原型如下:
template <class InputIterator, class OutputIterator, class UnaryPredicate>
OutputIterator copy_if (InputIterator first, InputIterator last,
OutputIterator result, UnaryPredicate pred)
{
while (first!=last) {
if (pred(*first)) {
*result = *first;
++result;
}
++first;
}
return result;
}
使用方法如下:
int main () {
std::vector<int> foo = {1,2,3,-1,-2};
std::vector<int> bar (foo.size());
auto it = std::copy_if (foo.begin(), foo.end(), bar.begin(), [](int i){return (i<0);} );
bar.resize(std::distance(bar.begin(),it));
std::cout << "bar contains:";
for (int& x: bar) std::cout << ' ' << x;
std::cout << '\n';
return 0;
}
上面代码输出结果为:bar contains: -1 -2。
PS:std::distance是计算两个迭代器区间范围内的元素数。
4.4 iota 算法
算法库中该算法可以用来在固定的数组上生成有序数列。使用方法如下:
int main () {
int numbers[10];
std::iota (numbers,numbers+10,100);
std::cout << "numbers:";
for (int& i:numbers) std::cout << ' ' << i;
std::cout << '\n';
return 0;
}
上面代码运行结果为:numbers: 100 101 102 103 104 105 106 107 108 109
由运行结果可知,算法给固定长度数组进行了初始化,初始化的值为第三个参数自增。
4.5 minmax_elemen
该算法可以同时获得数组或者容器中的最大值和最小值,使用方法如下:
int main () {
std::vector<int> foo {3,7,2,9,5,8,6};
auto result = std::minmax_element (foo.begin(),foo.end());
std::cout << "min is " << *result.first;
std::cout << ", at position " << (result.first-foo.begin()) << '\n';
std::cout << "max is " << *result.second;
std::cout << ", at position " << (result.second-foo.begin()) << '\n';
return 0;
}
上面代码运行结果为:
min is 2, at position 2
max is 9, at position 3
4.6 is_sorted 和is_sorted_until算法
使用方法如下:
int main () {
std::array<int,4> foo {2,4,1,3};
auto pos = std::is_sorted_until(foo.begin(),foo.end());
for(auto it =foo.begin();it != pos;it++)
{
std::cout<<*it<<", ";
}
std::cout<<std::endl;
bool isSorted = std::is_sorted(foo.begin(),foo.end());
if(!isSorted)
{
std::cout<<"数组为非完全排序"<<std::endl;
}
return 0;
}
代码运行结果如下:
2, 4,
数组为非完全排序