当前位置: 首页 > article >正文

C++ 基础语法 一

C++ 基础语法 一

文章目录

  • C++ 基础语法 一
    • const 限定符
    • 常量指针
    • 类型别名
    • auto
    • decltype
    • QString
    • vector
    • 迭代器
    • 指针和数组
    • 显示转换
      • static_cast
      • const_cast
    • 函数
      • 尽量使用常量引用
      • 数组形参
      • 不要返回局部对象的引用和指针
      • 返回数组指针
    • C++四种转换
    • 内联函数
    • constexpr函数
    • 函数指针

const 限定符

const对象一旦创建后 他的值就不能再改变 所以const对象必须初始化,常量特征只有是在执行改变其值才会发挥作用,默认情况下,const对象仅在文件内有效,多个文件内有同名const 变量其实是等同于不同文件分别定义了独立变量。如果要多个文件共享一个const变量 需要使用 extern

exten const int bufSize = 512 该常量可以被其他文件访问

常量指针

         int i=42;
    int *const curErr = &i;  // 把 * 放在const 前面代表这个指针是一个常量,不能改变指正本身的值 而非指向的那个值
    cout<<curErr<<" "<<*curErr<<endl;
    // 0x61fe14 42
    i=5;
    cout<<curErr<<" "<<*curErr<<endl;
    // 0x61fe14 5
    const double pi = 3.1415926;
    const double *const pip = &pi; // pip是一个常量对象的常量指针

类型别名

typedef double wages;    //wages 是double的别名
using si = sales_item;   // si是sales_item的别名

auto

// 使用auto 也能在一条语句中声明多个变量,因为声明语句只有一个基本数据类型,所以该语句中所有的变量的初始基本数据类型必须都一样
    auto i = 0,*p = &i; // 正确
    auto sz = 0,pi = 3.14;  // 错误 sz和pi类型不一致

decltype

选择并返回操作数的数据类型

decltype(f()) sum = x // sum类型就是函数f的返回类型

QString

      string s1 = "hello ";
    string s2 = "world";
    string s3 = s1+s2;
    cout<<&s1<<" "<<&s2<<" "<<&s3<<endl;
    s1 += s2;  // 直接在s1后面追加 不会创建对象
    cout<<&s1<<" "<<&s2<<endl;

当把string对象和字符字面值以及字符串字面值混在一条语句使用时,必须确保每个加法运算符的
两侧只有有一个是string,字符串的字面值不是string 是 const char []

string s1("hello world!!!");
    int punct_cnt = 0;
    for(auto c : s1){
        if(ispunct(c)){
            punct_cnt++;
        }
    } 统计是标点符号的个数

// 通过引用修改范围变量的本身的值
string s1("hello world!!!");
    for(auto &c : s1){
        c = toupper(c);
    }
    cout<<s1<<endl;

vector

本身是模板而非类型,由vector生成的类型必须包含vector中元素的类型,例如vector,模板本身不是类或函数 ,相反可以将模板看做为编译器生成类或函数编写的一份说明。编译器根据模板创建的类或函数的过程称为实例化。

      // 如果初始化时使用了花括号的形式但是提供的值又不能用来初始化,这时候就要考虑用这样的值
来构造vector对象了。
    vector<int> v1{10}; //初始化v1 有一个元素 就是10
    printf("%d\n",v1.size());
    vector<string> v2{10}; // 10个空字符串
    printf("%d\n",v2.size());

迭代器

标准库类型使用iterator和const_iterator来表示迭代器类型

vector<int>::iterator it;  // it 可以读写vector<int>的元素
    string::iterator it2;  // it2 可以读写string的元素
    vector<int>::const_iterator it3; // it3 只能读元素 不能写元素
    string::const_iterator it4; // it4 只能读元素 不能写元素

const_iterator 和常量指针差不多 能读取但不能修改它所指的元素值 ,相反iterator可读可写。为了方便我们得到const_iterator 类型返回值 ,C++11提供了两个新函数 分别是cbegin 和 cend;

指针和数组

在C++语言中指针和数组有着非常密切的联系 ,使用数组的时候编译器会把他转换为指针,在很多用到数组名字的地方,编译器都会自动的将其转换为一个指向数组首元素的指针。指向数组的指针拥有更多功能,数组的指针全部支持,特别注意尾后指针不能执行解引用和递增操作

         int arr[] = {1,2,3,4,5};
    for(int * b = arr;b!=arr+5;b++){
        cout<<*b<<" ";
    }

    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    int *beg = begin(arr); //beg 指向arr的第一个元素 begin 是定义在iterator头文件中的一个函数 ,用来返回一个指向arr首元素的指针
    int *last = end(arr); //last 指向arr的尾元素的下一个位置 end 是定义在iterator头文件中的一个函数 ,用来返回一个指向arr尾元素的下一个位置的指针
    while (beg != last)
    {
        cout<<*beg<<endl;
        ++beg;
    }

c标准库string函数 ,使用此类函数的指针必须指向以空字符作为结束的数组,例如:

char ca[] = {'C','+','+'}; //不是一个以空字符结束的字符串
cout<<strlen(ca)<<endl;    //严重错误 strlen是一个计算以空字符结束的字符串长度的函数,但是ca不是一个以空字符结束的字符串,
strlen函数将有可能沿着ca之后的内存继续查找,直到找到一个空字符为止
    

不能直接用string对象直接初始化指向字符的指针。为了完成该功能,string专门提供了一个名为c_str 成员函数

char * string = s // 错误 不能用string对象初始化char*
const char * str = s.c_str()   // 正确

可以使用数组初始化vector对象 ,允许使用数组来初始化vector对象 。要实现这一目的只需要指明拷贝区域的首元素地质和尾后地址就行。

int int_arr[] = {1,2,3,4,5,6,7,8,9,0};
vecotr<int> ivec(begin(int_arr),end(int_arr));]

最外层的循环控制变量声明成引用类型 ,这是为了避免数组被自动转换成指针 ,如果不用引用类型 编译器会初始化row 时会指向数组首元素的指针 这样便是得到int * ,显然内循环就不合法了,要使用范围for语句处理多维数组 除了最内层的循环外,其他的所有的循环变量都应该是引用类型

int ia[3][4] = {
        {0,1,2,3},
        {4,5,6,7},
        {8,9,10,11}
    };
    for(auto &row : ia){  
        for (auto col : row)
        {
            cout<<col<<endl;
        }
    }

显示转换

一个命名的强制转换具有如下形式: cast-name<type> (expression);

case-name 是 static_cast dynamic_cast const_cast reinterpret_case

static_cast

任何具有明确意义的类型转换,只要不包含底层的const,都可以使用static_cast。通过一个运算对象强制转换成double类型就能使表达式执行浮点数除法

// 进行强制类型转换
    double slope = static_cast<double>(5)/2;    

static_cast 对于编译器无自动执行的类型转换也非常有用。例如我们可以使用static_cast 找回存在的void* 指针 强制转换结果将与原始的地址值相等。

        int d = 3.14;
    void * p = &d;  // void * 指针可以存放任意对象的地址
    double *dp = static_cast<double*>(p); // 不能直接赋值,需要强制类型转换

const_cast

const_cast只能改变运算对象的底层const

    const char *pc;
    char *pcc = const_cast<char*>(pc);  // const_cast 只能改变底层const 通过p写值是未定义的行为

对于将常量对象转换成非常量对象的行为,我们一般称其去const 性质,一旦去掉了某个对象的const性质,编译器就不在阻止我们对该对象进行写操作。只有const_cast 能改变表达式的常量属性。

函数

尽量使用常量引用

把函数不会改变的形参定义成普通的引用是一种比较常见的问题,这么做会给函数调用者带来一个误导即函数可以修改他的实参值。此外使用引用而非常量引用会极大的显示函数所能接受的实参类型。我们不能把const对象 ,字面值或者需要类型转化的对象传递给普通的引用形参。

数组形参

数组的两个特殊性质:不允许拷贝数组以及使用数组时会将其转换成指针,因为不能直接拷贝数组,所以不能使用值传递的方式使用数组参数,因为数组会被转换成指针,所以当我们为函数传递一个数组时,实际传递的是指向数组首元素的指针。

当和其他使用数组的代码一样,以数组作为形参的函数必须确保使用数组不会越界。当函数不需要对数组元素执行写操作的时候,数组形参应该是指向const的指针,只有当函数确实要改变元素的时候,才把形参定义成指向非常量的指针

void print(int (&arr)[10]){ // c++ 允许将变量定义成数组的引用
    for(auto i:arr){
        cout<<i<<" ";
    }
}

f(int &arr[10]) arr是引用数组
f(int (&arr)[10] arr是具有10个整数的整形数组的引用

C++ 引用的数组和数组的引用-CSDN博客

不要返回局部对象的引用和指针

函数完成之后,他所占用的存储空间也会随之被释放,因此函数终止意味着局部变量的引用将指向不在有效的内存区域。main 函数不能调用自己

返回数组指针

数组不能拷贝,所以函数不能返回数组,不过,函数可以返回数组的指针或引用,想要定义一个返回数组的指针或引用的函数比较繁琐,但是有一些方法可以简化这一任务,其中最直接的方法就是使用类型别名

C++四种转换

内联函数

  1. 内联函数可以避免函数调用的开销,将函数指定为内联函数 ,通常就是将它在每一个调用点上内联的展开 例如
    1. cout<<shorterString(s1,s2) <<endl;在编译过程中会自动展开成’cout << (s1.size()<s2.size() ? s1 : s2)<<endl;
  2. 内联说明只是向编译器发出的一个请求,编译器可以忽略这个请求。
  3. 内联机制用于优化规模较小,流程直接的频繁调用的函数,很多编译器都不支持内联的递归调用

constexpr函数

  1. constexper 函数是指用于常量表达式的函数,函数的返回类型及其所有的形参的类型都得是字面值类型。而且函数体中必须有且仅有一条return 语句
    • constexper int new_sz() {return 42;}
  2. 执行该语句时,编译器对把constexper函数的调用替换成其结果值,为了能在编译过程中随时展开,constexper函数被隐式的指定为内联函数,constexper函数体内也可包含其他语句,只要这些语句在运行时不进行任何操作就行。
    • constexper size_t scale(size_t cnt) return {new_sz() * cnt;} 如果arg是常量表达式,则scale(arg) 也是常量表达式
  3. 把内联函数和constexper函数 放在头文件内,内联函数和constexper函数可以在程序中多次定义,他的多个定义必须完全一致

函数指针

  1. 函数指针指向的是函数而非对象,和其他指针一样,函数指针指向某种特定类型,函数的类型由他返回类型和形参类型共同决定,与函数名无关。
    • 比较两个string 对象长度bool lengthCompare(const string& ,const string &);该函数类型是bool (const string &,const string &)。 想要声明一个可以指向该函数的指针,只需要用指针替换函数名即可// pf 指向一个函数,该函数的参数是两个const string 的引用,返回值是bool类型bool (*pf) (const string &,const string &);pf 两端的括号必不可少,如果不写这对括号,则pf是一个返回值为bool指针的函数
  2. 当我们把函数名作为一个值使用时,该函数自动的转换成指针。
    • 按照如下形式我们可以将lengthCompare的地址赋值给pf;pf = lengthCompare; pf指向名为lengthCompare的函数pf = &lengthCompare; 等价的赋值语句,取地址符是可选的
    • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  3. 我们可以为函数指针赋值一个nullptr 或者 值为0的整形常量表达式,表示该指针没有指向任何函数。
  4. 重载函数的指针,当我们使用重载函数时,上下文必须清晰地界定到底应该选用那个函数,编译器会通过函数的形参列表和返回值确定选用那个函数,指针类型必须与重载函数中某一个精确匹配
  5. 函数指针形参和数组类似,虽然不能定义函数类型的形参,但是形参可以是指向函数的指针,此时,形参看起来是函数类型,实际上却是当成指针使用。
第三个形参是函数类型,他会自动转换成指向函数的指针 
void userBigger(const string& s1,const string& s2 , bool pf(const string & , const string &)); 

等价声明:显示的将形参定义成指向函数的指针 
void userBigger(const string& s1,const string& s2 , bool*pf)(const string & , const string &)); 

我们可以直接把函数作为实参使用,此时他会自动转换成该函数的指针 
userBigger(s1,s2,lengthCompare) 自动将函数lengthCompare 转换成指向该函数的指针
  1. 返回指向函数的指针,我们必须把返回的类型写成指针类型,编译器不会自动的将函数返回类型当成对应的指针类型处理,与往常一样要想声明一个返回函数指针的函数,最简单的办法是使用类型别名。
using F = int(int*,int); 
F是函数类型,不是指针 
using PF = int(*)(int*,int); 
PF是函数指针 ---- 这里和函数类型的形参不一样,返回类型不会自动的转换成指针,我们必须显式的将返回类型指定为指针 

PF f1(int) 正确 F* f1(int) 正确 显式指定返回值类型指向函数的指针 
F f1(int) 错误 不能返回一个函数

http://www.kler.cn/a/376550.html

相关文章:

  • T10打卡—数据增强
  • 数据结构+算法分析与设计[15-18真题版]
  • 【鸿蒙新闻】10月29日警用鸿蒙开发者大会在北京胜利召开,开启智慧应用新时代!
  • 服务器数据恢复—DELL EqualLogic PS6100系列存储简介及如何收集故障信息?
  • 034_Structural_Transient_In_Matlab结构动力学问题求解
  • linux-UART
  • 计算机低能儿从0刷leetcode | 34.在排序数组中查找元素的第一个和最后一个位置 | 二分法
  • 微服务实战系列之玩转Docker(十六)
  • 一文解析axios源码
  • uniapp MD5加密
  • 网络请求优化:理论与实践
  • Oracle视频基础1.3.7练习
  • 【python】爬虫
  • APISQL企业版离线部署教程
  • 二叉苹果树
  • Redis主从复制:全量复制与增量复制区别与联系
  • scala---10.30
  • 《Python爬虫:价格侦探的奇妙冒险》
  • 「C/C++」C/C++ 之 循环结构详解
  • volatile变量
  • Vue2——单页应用程序路由的使用
  • SpringBoot实现国密通信
  • 基于MATLAB驾驶行为的疲劳实时检测研究
  • android数组控件Textview
  • sublime Text中设置编码为GBK
  • 电子时钟--html+css+js实现