c++11部分语法

本文详细介绍了C++11引入的一些重要语法特性,包括列表初始化、变量类型推导、范围for循环、final与override的使用、委派构造函数、默认函数控制以及右值引用。列表初始化支持多参数构造,变量类型推导简化了类型声明,范围for简化了容器遍历。final用于禁止继承和重写虚函数,override确保函数正确重写。委派构造函数减少代码冗余,而默认函数控制则允许显式启用或禁用默认构造函数。右值引用提高了效率,主要用于移动构造和移动赋值操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

 

1.列表初始化

2.变量类型推导

3.范围for

4.final与override

5.委派构造函数

5.1构造函数冗余造成重复

5.2委派构造函数

6.默认函数控制

6.1显示缺省函数

6.2删除默认函数

7.右值引用


1.列表初始化

	int arr1[] = { 1,2,3,4,5 };
	int arr2[5] = { 0 };
	
	vector<int> v1{ 1,2,3 };
	vector<int> v2 = {1,2,3 };
	
	list<int> l1{ 1,2 };//=

	map<int, int> m1  { {1,1},{2,2} };//=

C++98单参数的构造函数支持隐式类型的转换,c++11多参数也支持。如果不想它支持,可以在构造函数前加关键字explicit。

C++11中的vector新增了一个构造函数,参数是initializer_list,这是一个模板,可变参数列表,list也是这样支持的。

Vector(initializer_list<T> l)
    :_capacity(l.size())
    ,_size(0)
{
    _array = new T[_capacity];
    for(auto e : l)
        _array[_size++] = e;
}
template<class K, class V>
class map
{
    map(initializer_list<pair<K,V>>& l)
    {}
};

2.变量类型推导

在定义变量时,必须给出变量的实际类型。根据对象推演出类型

cout<<typeid(p).name()<<endl;//打印出p的类型

decltype(p) p1;//定义出一个p类型的p1,反向推演。

3.范围for

遍历容器,由迭代器支持,编译器遇到范围for,本质上就把它转化成了迭代器的代码。

4.final与override

final:①放在类的后面,这个类不能被继承,②修饰虚函数,这个虚函数不能被重写

override:修饰子类的虚函数,强制检查子类的虚函数有没有完成重写,如果没有就会报错。帮助我们去检测有没有重写。

5.委派构造函数

5.1构造函数冗余造成重复

一个类有多个构造函数,为了减少程序员书写构造函数的时间。通过委派其他构造函数,多构造函数的类编写更加容易。

5.2委派构造函数

在构造函数的初始化列表阶段调用共用的构造函数,而自己特别的需要做的事在函数里面完成。

6.默认函数控制

6.1显示缺省函数

我写了默认函数,编译器就不会生成默认构造函数,可是我又需要这个默认构造函数,此时可以使用

类名() = default;

强制编译器生成默认构造函数

6.2删除默认函数

 禁止编译器生成默认的拷贝构造函数以及赋值运算符重载,防拷贝和赋值,浅拷贝和单例模式

A(const A&) = delete;    
A& operator(const A&) = delete

7.右值引用

// a是左值, 10是右值
int a = 10;
int b = a;

int& lr1 = a;//左值引用

int && rr2 = 10;//右值引用

//左值引用能不能引用右值?答案是不能的

//int& lr2 = 10;
//但是可以用const,const引用既能引用左值又能引用右值
const int& lr2 = 10;

//右值引用能否引用左值?答案也是否定的

//但是可以引用move

int&& rr2 = (move)a;

赋值符号左边的值是左值,右边的值不一定是右值。左值是可以被改变的值。

左值引用 的作用:

  1. 提高效率,减少拷贝(深)
  2. 里面改变,外面能看到

常量是右值,表达式的返回值是右值,const修饰的不是右值。

 C++11中的右值:

  • 纯右值:常量,运算表达式
  • 将亡值:声明周期将要结束的值,例如函数返回时的临时对象(拷贝的那个)

引用将亡值有意义,移动构造,移动赋值,没有去做真的拷贝,高效。

class String
{
public:
	String(const char* str = "")
		:_str(new char[strlen(str)+1])
	{
		strcpy(_str, str);
	}

	// s1(s2)
	// 拷贝构造
	String(const String& s)
		:_str(new char[strlen(s._str) + 1])
	{
		cout << "String(const String& s)" << endl;
		strcpy(_str, s._str);
	}

	String& operator=(const String& s)
	{
		cout << "String& operator=(const String& s)" << endl;
		if (this != &s)
		{
			delete[] _str;
			_str = new char[strlen(s._str) + 1];
			strcpy(_str, s._str);
		}

		return *this;
	}

	// 移动构造
	String(String&& s)
		:_str(s._str)
	{
		cout << "String(String&& s)" << endl;
		s._str = nullptr;
	}

	// 移动赋值
	// s1 = die;
	String& operator=(String&& s)
	{
		cout << "String& operator=(String&& s)" << endl;
		swap(_str, s._str);
		return *this;
	}

	~String()
	{
		delete[] _str;
	}

	const char* c_str()
	{
		return _str;
	}
private:
	char* _str;
};

String operator+(const String& s1, const String& s2)
{
	String ret(s1);
	//ret += s2;

	return ret;
}

String GetString(char* pStr)
{
	String ret(pStr);
	return ret;
}

#include <queue>

int main()
{
	//String s = GetString("hello");
	/*String s;
	s = GetString("hello");*/
}

右值引用最大的作用就是做参数,STL的库里面的insert(queue,list)是一个左值引用,emplace的参数是一个可变参数的右值引用。

	String s("hello");
	queue<String> q;

	q.push(s);//调用拷贝构造

        //调用移动构造
	q.push(move(s));
        q.emplace(move(s));

	q.push("world");//拿的是world的临时对象,是右值(将亡值),如果没有将亡值这种设计,消耗很大

move函数将一个左值变为一个右值,右值被认为是将亡值,别人可以把这个对象抽空。

右值引用减少深拷贝,尽量多去调用移动构造。利用将亡值。尽量push临时对象。

	queue<pair<int, int>> prq;
	pair<int, int> pr(1, 1);

	prq.push(pr);//左值

	prq.push(make_pair(2,2));//右值
	prq.emplace(3, 3);//emplace是一个可变参数,强制化了必须是右值

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值