C++11基础学习系列三


概述

随着自己学习C++11的进度,今天记录和实战C++11的战果。废话少说,直接记录C++11的点滴。

数组

在前面学习系列里面,介绍了模板容器类vector,是一个单链表。今天来了解一下C++中的数组。数组也是存放相同类型的容器,数组的大小是固定不变的(编译时数组的维度必须是已知的)。如果想动态操作容器(增加,删除等)或者事先不知道容器的大小,请使用vector。 在使用数组时注意一下几点: 1.数组的维度必须是常量表达式,在编译时是已知的。

#错误的,无法通过非常量表达式初始化数组,请使用constexpr.
unsigned int size = 12;
#正确的
constexpr unsigned int size = 12;
#getsize()返回结果必须是常量表达式。
int a[size/getsize()]={1,2,3};

2.数组的类型不能使用auto关键字推断类型。 3.显示初始化数组元素时,可省略数组的维度。

int a[]={1,2,3};
string b[4]={"a","b"};

4.数组时不允许copy和赋值,不能将数组的内容拷贝给其他数组作为初始值,也不能为其他数组赋值。

int a[]={1,2,3};
// 错误的
int b[] = a;
// 错误的
b=a;

5.指针和数组很多细节需要注意,包括通过指针访问数组元素。比如:

// temp是含有10个整形指针的数组
int *temp[10];
// temp是个指针,指向一个含有10个整数的数组。
int (*temp)[10];
// temp引用一个含有10个整数的数组。
int (&temp)[10];
string nums[]={"a","b"};
// 指向数组的首元素的指针
string *p = nums;
// p1的类型是指针类型,指向的是string*
auto(nums) p1;
// p2 是一个字符串数组
decltype(nums) p2 = {"c","d"};
//C++11引入新的标准,来获得数组的首元素地址和末尾元素的下一个位置的地址。
int nums [] = {2,3,4,5};
int *start = begin(nums);
int *last = end(nums);

显示转换

强制类型显示转换有static_cast,dynamic_cast,const_cast和reinterpret_cast.其中dynamic_cast是运行时识别的一种技术,后面会详细介绍。

  • static_cast:任何具有明确定义的类型转换(不包含底层const),比如:数值类型转换,void* 类型的转换。(const int * const a 其中靠近a的为顶层cast,远离a的为底层cast。) int i,j; double k = static_cast<double>(j)/i; void *p = &i; int *t = static_cast<int*>(p);
  • const_cast智能改变运算对象的底层const,它可以去掉底层const的性质。 const string *p; string *q = const_cast(string*)(p);
  • reinterpret_cast为运算对象的位模式提供较低层次上的重新解释,由于是对象的位模式,所以严重依赖硬件的架构。实际运用较少。

函数

再详细讲解C++11函数对象之前,首先要熟悉看一下局部对象,局部对象包括:自动对象和局部静态对象

函数局部对象

局部对象 形参和函数体内定义的变量,局部变量还会隐藏外层作用域的同名对象。在所有函数体之外定义的对象存在于程序的整个执行过程,当程序启动时被创建,知道程序结束时被创建。

  • 自动对象 存在于块执行期间的对象,形参是一种自动对象。如果变量本身含有初始值,就用这个初始值进行初始化;如果不包含初始值,执行默认初始化,内置类型的默认初始化将产生未定义的值。
  • 局部静态对象 通过static将局部对象定义的,执行第一次经过对象定义的语句时初始化,知道程序结束时销毁,内置类型的局部静态变量初始化为0.

函数参数传递

依据形参传递的类型将函数传递,分为按引用传递和按值传递,当形参为引用类型时是按引用传递,实际是传递实参的别名。当实参的值被拷贝给形参时,形参和实参是两个互相独立的对象,这是按值传递。还有一种是指针形参,指针是按值传递的,当执行指针拷贝时,拷贝的是指针的值。所以你可以通过指针来修改实参的值。 由于拷贝大的类型对象或者容器对象比较低效,甚至有的类型(IO类型)是不支持拷贝的,这时我们尽量采用按引用传递,这样可以避免拷贝付出的代价。如果函数内无须改变参数的值时,最好将其声明为常量引用。

const形参和实参

顶层const作用于对象本身。

// 顶层const对象,不能改变a
const int a = 12;
// 当拷贝a时,忽略了顶层const的影响。
int i = a;
// 顶层const对象,不能改变p的值。
int * const p = &i;
// 但可以通过p所指向的地址修改它的value。
*p=12;

当用实参初始化形参时会忽略掉顶层const,形参的顶层const会被忽略掉。

//func既可以接收int,也可以接收const int,但是不能修改i的值。
void func(const int i);

尽量使用常量引用

可变形参的函数

可变形参是通过initializer_list实现,但是要求类型一致。

#include <iostream>

void message(std::initializer_list<std::string> temp){
    for(auto i:temp){
        std::cout << i << std::endl;
    }
}

int main() {
    message({"hello","world","brian"});
    return 0;
}

返回类型

1.不要返回局部对象的引用或者指针 由于局部对象在函数调用完后,局部对象所占用的存储空间随之被释放。 2.引用返回左值 调用一个返回引用的函数得到左值,其它返回类型为右值。

#include <iostream>
char &get_char(std::string & a,std::string::size_type index) {
    return a[index];
}
int main() {
    std::string s="hello";
    get_char(s,2)='E';
    std::cout <<s<< std::endl;
    return 0;
}
# 输出为
hEllo

3.通过列表初始化返回多个值

#include <iostream>
#include <vector>

std::vector<std::string> get_err(){
    return {"hello","error"};
}

int main() {
    auto list = get_err();
    for(auto i : list){
        std::cout << i << std::endl;
    }
    return 0;
}
#输出为
hello
error

4.返回数组的指针 由于数组不能被拷贝,所以函数不能返回数组,但是可以返回数组的指针或引用。 在C语言中通过typedef来重命名一个类型名称,在C++中通过using来,虽然typedef可以在c++继续使用,但是还是建议使用using.

typedef int arr[10]; //arr是类型别名,表示含有10个整数的数组。
等价于
using arr = int[10];
int (*p2)[10] = &arr; //p2是一个指针指向一个含有10个整数的数组

值得注意的是如果要返回数组指针的函数,稍微麻烦一些: Type(*function(parameter_list))[dimension] int(*func(int i))[10],func是一个函数指针,指向一个返回值为10个整数的数组。 由于这样声明太过于麻烦,所以在c++11标准中通过尾置返回类型,任何函数都能使用尾置返回类型。上述的声明可以通过: auto func(int i)->int(*)[10]

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java一日一条

继承、接口与多态的相关问题

继承:通过继承实现代码复用。Java中所有的类都是通过直接或间接地继程java.lang.Object类得到的。继承而得到的类称为子类,被继承的类称为父类。子类...

912
来自专栏老九学堂

最新Java高薪面试题+答案+解析!

今天老九君给大家分享一些Java面试需要的题目哟~ 01 anonymousinnerclass(匿名内部类)是否可以extends(继承)其它类,是否可以im...

4527
来自专栏老马说编程

计算机程序的思维逻辑 (8) - char的真正含义

看似简单的char 通过前两节,我们应该对字符和文本的编码和乱码有了一个清晰的认识,但前两节都是与编程语言无关的,我们还是不知道怎么在程序中处理字符和文本。 ...

1826
来自专栏猿人谷

C++重要知识点小结---1

1.C++中类与结构的唯一区别是:类(class)定义中默认情况下的成员是private的,而结构(struct)定义中默认情况下的成员是public的。 2....

1949
来自专栏老司机的技术博客

人人都能学会的python编程教程12:函数的参数

Python的函数定义非常简单,也非常灵活。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还...

4847
来自专栏从流域到海域

Python yield关键字 和 Generator(生成器)

Generators functions allow you to declare a function that behaves like an itera...

26010
来自专栏IT派

Java面试中常被问到的几大技术难题

大家在平常面试java的过程中都会遇到哪些难题呢?还有一些即将去面试java的童鞋们,你们想知道技术面试中会涉及到哪些点吗?达妹为你整理Java面试中会被问到的...

1210
来自专栏河湾欢儿的专栏

第五节正则

882
来自专栏老司机的技术博客

宝宝都能学会的python编程教程12:函数的参数

Python的函数定义非常简单,也非常灵活。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还...

3586
来自专栏CodeSheep的技术分享

Java编程思想学习录(连载之:初始化与清理)

2018

扫码关注云+社区

领取腾讯云代金券