首页 > 编程语言 >C++11稳定性与兼容性机制

C++11稳定性与兼容性机制

时间:2024-01-16 23:33:02浏览次数:28  
标签:11 std 兼容性 string int 函数 long C++ 断言

字符串的原始字面量

使用样例 : R “xxx(raw string)xxx” 其中括号内的即是原始字面量,可以直接表示字符串而不需要做转义,需注意括号前后的xxx字符串会被忽略且必须一样

string str = "D:\hello\world\test.text";  // 1
cout << str << endl;
string str1 = "D:\\hello\\world\\test.text"; // 2
cout << str1 << endl;
string str2 = R"这里写啥都行但必须左右一样(D:\hello\world\test.text)这里写啥都行但必须左右一样"; // 3
cout << str2 << endl;

运行结果
1:D:helloworld    est.text
2:D:\hello\world\test.text
3:D:\hello\world\test.text

long long

C++11 标准要求 long long 整型可以在不同平台上有不同的长度,但至少有64位。long long 整型有两种∶

1、long long – 对应类型的数值可以使用 LL (大写) 或者 ll (小写) 后缀 long long num1 = 123456789LL; long long num2 = 123456789ll;

2、unsigned long long – 对应类型的数值可以使用 ULL (大写) 或者 ull (小写) 或者 Ull、uLL (等大小写混合)后缀 unsigned long long num1 = 123456789ULL; unsigned long long num2 = 123456789ull; unsigned long long num3 = 123456789uLL; unsigned long long num4 = 123456789Ull;

同其他的整型一样,要了解平台上 long long大小的方法就是查看(或 )中的宏与long long整 型相关的一共有3个:

LLONG_MIN – 最小的long long值 LLONG_MAX – 最大的long long 值 ULLONG MAX – 最大的 unsigned long long 值

类成员的快速初始化

C++98 : 类的非静态成员,必须在构造函数中进行初始化 类的静态成员,必须在类的外部进行初始化

struct Base 
{
    Base() : a(250) {}
    Base(int num) : a(num) {}

    int a;
    int b = 1;	
    static int c = 0;	
    static const double d = 3.14;	
    static const char* const e = "i am luffy";	
    const static int f = 0;	
};

如果按照 C++98 标准来解读上面这段代码 ,其中有这么几行语法是错误的: 第7行:类的非静态成员,必须在构造函数中进行初始化

第8行:类的静态成员,必须在类的外部进行初始化

第9行:类的静态常量成员,但不是整形或者枚举,无法通过编译

如果使用 g++ 可能发现就地初始化 double 类型的静态常量是可以通过编译的,不过这实际是 GNU 对C++的一个扩展,并不遵从C++ 标准。

第10行:类的静态常量成员,但不是整形或者枚举,无法通过编译

第8、9、10行的变量初始化方式是一样的,都是在类的外部

C++11: 在进行类成员变量初始化的时候,允许在定义类的时候在类内部直接对非静态成员变量进行初始化,在初始化的时候可以使用等号 = 也可以使用花括号 {} 。

class Test
{
private:
    int a = 9; 
    int b = {5};
    int c{12};
    double array[4] = { 3.14, 3.15, 3.16, 3.17};
    double array1[4] { 3.14, 3.15, 3.16, 3.17 };
    string s1("hello");     // error
    string s2{ "hello, world" };
};

第9行:错误,不能使用小括号() 初始化对象,应该使用花括号{}

类内部赋值和初始化列表的覆盖

class Init
{
public:
    Init(int x, int y, int z) :a(x), b(y), c(z) {} // 初始化列表

    int a = 1; // 内部赋值
    int b = 2;
    int c = 3;
};

int main()
{
    Init tmp(10, 20, 30);
    cout << "a: " << tmp.a << ", b: " << tmp.b << ", c: " << tmp.c << endl;
    return 0;
}
//  初始化列表的值会覆盖内部初始化的值
=====输出=====
a: 10, b: 20, c: 30

final

C++中增加了final关键字来限制某个类不能被继承,或者某个虚函数不能被重写,和Java的final关键字的功能是类似的。如果使用final修饰函数,只能修饰虚函数,并且要把final关键字放到类 (就成了断子绝孙类) 或者函数的后面。

class Base
{
public:
    virtual void test()
    {
        cout << "Base class...";
    }
};

class Child : public Base
{
public:
    void test() final
    {
        cout << "Child class...";
    }
};

class GrandChild : public Child
{
public:
    // 语法错误, 不允许重写
    void test()
    {
        cout << "GrandChild class...";
    }
};

override

override关键字确保在派生类中声明的重写函数与基类的虚函数有相同的签名,同时也明确表明将会重写基类的虚函数,这样就可以保证重写的虚函数的正确性,也提高了代码的可读性,和final一样这个关键字要写到方法的后面。使用方法如下:

class Base
{
public:
    virtual void test()
    {
        cout << "Base class...";
    }
};

class Child : public Base
{
public:
    void test() override
    {
        cout << "Child class...";
    }
};

class GrandChild : public Child
{
public:
    void test() override
    {
        cout << "Child class...";
    }
};

上述代码中第13行和第22行就是显示指定了要重写父类的test()方法,使用了override关键字之后,假设在重写过程中因为误操作,写错了函数名或者函数参数或者返回值编译器都会提示语法错误,降低了出错的概率

模板的优化

在泛型编程中,模板实例化中需要注意:连续的两个右尖括号(>>)会被编译器解析成右移操作符,而不是模板参数表的结束。 Base<vector<int>> b;//在C++98/03标准会报错

新增了函数模板对默认参数的支持

#include <iostream>
#include <string>
using namespace std;

template <typename R = int, typename N>  // 模板1 
R func(N arg)
{
    return arg;
}

// 函数模板定义
template <typename T, typename U = char> // 模板2
void func(T arg1 = 100, U arg2 = 100)
{
    cout << "arg1: " << arg1 << ", arg2: " << arg2 << endl;
}


int main()
{
//模板1测试
    auto ret1 = func(520.1314);
//函数返回值类型使用了默认的模板参数,函数的参数类型是自动推导出来的为int类型。
    cout << "return value-1: " << ret1 << endl;

    auto ret2 = func<double>(52.134);
    cout << "return value-2: " << ret2 << endl;

    auto ret3 = func<int>(52.134);
    cout << "return value-3: " << ret3 << endl;

    auto ret4 = func<char, int>(100);
    cout << "return value-4: " << ret4 << endl;
 
//模板2测试

    func('a');
//func('a'):T自动推导为char,U使用的默认模板参数为char
    func(97, 'a');参数T被自动推导为int类型,U使用推导出的类型为char
    // func();    //编译报错,参数T没有指定默认模板类型,并且无法自动推导


    return 0;
}
===输出===
return value-1: 520
return value-2: 52.134
return value-3: 52
return value-4: d

数值类型与字符串类型的转换优化

数值转为字符串

使用to_string()方法可以非常方便地将各种数值类型转换为字符串类型,这是一个重载函,函数声明位于头文件<string>中 string pi = "pi is " + to_string(3.1415926);

字符串转为数值

使用stoX() 函数,X的含义:转int就是i, 转long 就是l, 转double就是d …

// 定义于头文件 <string>
int       stoi( const std::string& str, std::size_t* pos = 0, int base = 10 );
long      stol( const std::string& str, std::size_t* pos = 0, int base = 10 );
long long stoll( const std::string& str, std::size_t* pos = 0, int base = 10 );

unsigned long      stoul( const std::string& str, std::size_t* pos = 0, int base = 10 );
unsigned long long stoull( const std::string& str, std::size_t* pos = 0, int base = 10 );

float       stof( const std::string& str, std::size_t* pos = 0 );
double      stod( const std::string& str, std::size_t* pos = 0 );
long double stold( const std::string& str, std::size_t* pos = 0 );

str:要转换的字符串 pos:传出参数, 记录从哪个字符开始无法继续进行解析, 比如: 123abc, 传出的位置为3 base:若 base 为 0 ,则自动检测数值进制:若前缀为 0 ,则为八进制,若前缀为 0x 或 0X,则为十六进制,否则为十进制。 除去第一个参数外其他都有默认值, 一般使用默认值就够用了

样例

#include <iostream>
#include <string>
using namespace std;
int main()
{
    string str1 = "45";
    string str2 = "3.14159";
    string str3 = "9527 with words";
    string str4 = "words and 2";

    int myint1 = std::stoi(str1);
    float myint2 = std::stof(str2);
    int myint3 = std::stoi(str3);
    // 错误: 'std::invalid_argument'
    // int myint4 = std::stoi(str4);

    cout << "std::stoi(\"" << str1 << "\") is " << myint1 << endl;
    cout << "std::stof(\"" << str2 << "\") is " << myint2 << endl;
    cout << "std::stoi(\"" << str3 << "\") is " << myint3 << endl;
    // cout << "std::stoi(\"" << str4 << "\") is " << myint4 << endl;
}
===输出===
std::stoi("45") is 45
std::stof("3.14159") is 3.14159
std::stoi("9527 with words") is 9527

如果字符串中所有字符都是数值类型,整个字符串会被转换为对应的数值,并通过返回值返回 如果字符串的前半部分字符是数值类型,后半部不是,那么前半部分会被转换为对应的数值,并通过返回值返回 如果字符第一个字符不是数值类型转换失败

静态断言

断言(assertion)是一种编程中常用的手段。在通常情况下,断言就是将一个返回值总是需要为真的判断表达式放在语句中,用于排除在设计的逻辑上不应该产生的情况。

比如:一个函数总需要输入在一定的范围内的参数,那么程序员就可以对该参数使用断言,以迫使在该参数发生异常的时候程序退出,从而避免程序陷入逻辑的混乱。


从一些意义上讲,断言并不是正常程序所必需的,不过对于程序调试来说,通常断言能够帮助程序开发者快速定位那些违反了某些前提条件的程序错误。

如果我们要在C++程序中使用断言,需要在程序中包含头文件或,头文件中为我们提供了 assert 宏,用于在运行时进行断言。举例说明:

#include <iostream>
#include <cassert>
using namespace std;

// 创建一个指定大小的 char 类型数组
char* createArray(int size)
{
    // 通过断言判断数组大小是否大于0
    <strong>assert(size > 0);	// 必须大于0, 否则程序中断</strong>
    char* array = new char[size];
    return array;
}

int main()
{
    char* buf = createArray(0);
    // 此处使用的是vs提供的安全函数, 也可以使用 strcpy
    strcpy_s(buf, 16, "hello, world!");
    cout << "buf = " << buf << endl;
    delete[]buf;
    return 0;
}

程序使用了断言assert(expression) ,这是一个宏,它的参数是一个表达式,这个表达式通常返回一个布尔类型的值,并且要求表达式必须为 true 程序才能继续向下执行,否则会直接中断。

静态断言(编译时而非运行时检查)

在上面的例子中我们使用了断言 assert。但 assert是一个运行时断言,也就是说它只有在程序运行时才能起作用 。这意味着不运行程序我们将无法得知某些条件是否是成立的。
比如:我们想知道当前是32位还是64位平台,对于这个需求我们应该是在程序运行之前就应该得到结果,如果使用断言显然是无法做到的,对于这种情况我们就需要使用C++11提供的静态断言了。

静态断言的另一个好处是,可以自定义违反断言时的错误提示信息。静态断言使用起来非常简单,它接收两个参数:

标签:11,std,兼容性,string,int,函数,long,C++,断言
From: https://blog.51cto.com/u_14882565/9279154

相关文章

  • c++语法
    基本语法C++是一种通用的编程语言,具有面向对象的特性。以下是一些C++的基本语法:注释:在C++中,注释可以使用//表示单行注释,或者使用/**/表示多行注释。cppCopycode/*这是多行注释*/头文件:C++中使用头文件来引入库和声明函数。#include<iostream>//输......
  • c++基础
    c++基础#include<iostream>usingnamespacestd;//定义类AAclassAA{private:inta;//私有数据成员apublic://构造函数,用于初始化aAA(intvalue){a=value;}//公有成员函数,用于获取a的值intGetValue(){retur......
  • [POI2011] MET-Meteors
    [POI2011]MET-Meteors题面翻译ByteotianInterstellarUnion有\(n\)个成员国。现在它发现了一颗新的星球,这颗星球的轨道被分为\(m\)份(第\(m\)份和第\(1\)份相邻),第\(i\)份上有第\(a_i\)个国家的太空站。这个星球经常会下陨石雨。BIU已经预测了接下来\(k\)场陨......
  • C++:GDAL中CreateCopy()函数生成的栅格图像如何修改波段数?
      本文介绍基于C++语言GDAL库,为CreateCopy()函数创建的栅格图像添加更多波段的方法。  在C++语言的GDAL库中,我们可以基于CreateCopy()函数与Create()函数创建新的栅格图像文件。其中,CreateCopy()函数需要基于一个已有的栅格图像文件作为模板,将模板文件的各项属性信息(例如空......
  • Win11上安装repo以能够使用`repo sync`同步Android代码
    首先安装一个git然后获取安卓源码,参考https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/下载地址为https://mirrors.tuna.tsinghua.edu.cn/aosp-monthly/aosp-latest.tar解压tar文档,由于安卓代码逐渐使用python3脚本替代python2,而git-repo稳定版已不支持使用于Android源码......
  • C++学习日记 2024-1-16
    开始学习C++几天了,之前没有记录,从现在开始,记录一下学习过程复习与回忆:1.引用与指针共同优点:只用引用与指针,在传递参数时,可以减少拷贝,减少内存消耗,提高效率指针优点:指针比引用更强大,所有引用能做的事,指针都能做,指针缺点:危险,指针可以为空,指针指向地址,同一地址可以......
  • 1.11每日总结
    python也有不少缺点 运行速度,有速度要求的话,用C++改写关键部分吧。 国内市场较小(国内以Python来做主要开发的,目前只有一些web2.0公司)。但时间推移,目前很多国内软件公司,尤其是游戏公司,也开始规模使用他。 中文资料匮乏(好的Python中文资料屈指可数,现在应该变多了)。托......
  • C++(静态成员函数、静态成员变量)
    目录静态成员函数(StaticMemberFunctions)静态成员变量(StaticMemberVariables)在C++中,静态成员函数和静态成员变量是与类相关联而不是与类的实例相关联的。它们属于类而不是类的实例,并且可以通过类名访问,而不需要创建类的实例。静态成员函数(StaticMemberFunctions)静态成员......
  • 采用模块化方法设计的LMK1C1104DQFR、LMK1C1106PWR、LMK1C1108PWR(LVCMOS)时钟缓冲器系
    LMK1C110x1.8V、2.5V和3.3VLVCMOS时钟缓冲器系列1、概述LMK1C110x是的一款模块化、高性能、低偏斜、通用时钟缓冲器系列器件。整个系列采用模块化方法设计。提供三个不同的扇出选项:1:2、1:3、1:4。该系列所有器件均互相引脚兼容,并向后兼容CDCLVC110x系列,便于操作。该系列所......
  • c++程序加速方法
    1.将反复使用的数据存放在全局变量里面。需要重复使用的数据,比如加载的图片,CSV文件等数据,存放在全局变量里面,每次加载DLL时,只加载一次,直到卸载DLL,这些数据一直保持在内存中,避免重复加载,经过测试,这样处理之后,漏装检测的时间由2.5S降低到了1.5S,因为反复读取文件,图片是一个很消耗时......