C++新特性(侯捷)

这篇博客详细介绍了C++中的转换函数、非显式单参数构造函数、智能指针和仿函数。讨论了模板的成员模板、特化和模版模版参数,以及C++11的新特性,如可变参数模板、auto关键字和范围for循环。此外,还深入探讨了对象模型,包括vptr和vtbl在多态中的作用,以及const的使用规则和new、delete操作符的重载。

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

Conversion function转换函数

  • 转为其他类型
class Fraction
{
public:
	Fraction(int num, int den = 1)
	: m_numerator(num), m_denominator(den) {}
	// 转换函数,没有return type
	operator double() const{		// 转换函数
        return (double) (m_numerator / m_denominator);
    }
private:
	int m_numerator;	// 分子
	int m_denominator;	// 分母
};

Fraction f(3, 5);
double ans = 4 + f; 	// 调用operator double()将f转换为double

non-explicit-one-argument ctor

  • 转为对应的类对象
class Fraction
{
public:
	Fraction(int num, int den = 1)
	: m_numerator(num), m_denominator(den) {}

	Fraction operator+(const Fraction& f){
        return Fraction(...);
    }
private:
	int m_numerator;	// 分子
	int m_denominator;	// 分母
};

Fraction f(3, 5);
double ans = f + 4; 	// 调用non-explicit ctor将4转为Fraction,再调用operator+

考虑代码的二义性,需用explicit(明确的)关键字,一般用于构造函数前,或模版
explicit关键字的作用就是防止类构造函数的隐式自动转换
加上关键字explicit后,不允许再隐式转换

class Fraction
{
public:
	explicit Fraction(int num, int den = 1)
	: m_numerator(num), m_denominator(den) {}

	operator double() const{		// 转换函数
        return (double) (m_numerator / m_denominator);
    }

	Fraction operator+(const Fraction& f){
        return Fraction(...);
    }
private:
	int m_numerator;	// 分子
	int m_denominator;	// 分母
};

Fraction f(3, 5);
double ans = f + 4; 	// Error conversion from ‘double’ to ‘Fraction’ requested

pointer-like classes 智能指针

template<class T>
class shared_ptr
{
public:
	T& operator*() const
	{ return *px; }
	T* operator->() const
	{ return px; }
	shared_ptr(T* p) : px(p) { }

private:
	T* px;
	long* pn;
};

struct Foo
{
	...
	void method(void ){}
};

shared_ptr<Foo> sp(new Foo);

sp->method();
// => px->method();

function-like classes 所谓仿函数

  • class 中写了operator() 就是仿函数
template <class Pair>
struct select1st {
	const typename Pair::first_type& operator() (const Pair& x) const{
        return x.first;
    }
}

template 模版

member template 成员模版

  • 主要在标准库中的构造函数中出现,使其更富有弹性
template <class T1, class T2>
struct pair{
	typedef T1 first_type;
	typedef T2 second_type;

	T1 first;
	T2 second;

	pair()
    	: first(T1()), second(T2()) { }
	pair(const T1& a, const T2& b)
    	: first(a), second(b) { }
	
	// member template
	template <class U1, class U2>
	pair(const pair<U1, U2>& p)
    	: first(p.first), second(p.second) { }
};

//	T1, T2					U1, U2
pair<Base1, Base2> p(pair<Derived1, Derived2>());
  • 智能指针
template<typename _Tp>
class shared_ptr : public __shared_ptr<_Tp>{
...
	template<typename _Tp1>
	explicit shared_ptr(_Tp1* __p)
    	: __shared_ptr<_Tp>(__p){ }
...
};

Base* ptr = new Derived;	// up-cast
shared_ptr<Base> sptr(new Derived);	// 模拟up-cast

specialization,模版特化

template <class Key>			// 泛化
struct hash { };

template<>
struct hash<char> {				// 特化
	size_t operator()(char x) const{
        return x;
    }
};

template<>
struct hash<int> {
	size_t operator()(int x) const{
        return x;
    }
};

template<>
struct hash<long>{
	size_t operator()(long x) const{
        return x;
    }
};

partial specialization,偏特化

特化确定的参数,前面就只需要写template<>(_STL_TEMPLATE_NULL)

  • 模版参数个数的偏
template<typename T, typename Alloc=...>	// 模版参数
class vector
{
...
};

template<typename Alloc=...>
class vector<bool, Alloc>
{
...
}
  • 模版参数范围上的偏
template<typename T>
class C
{
...
};

template<typename T>
class<T*>
{
...
};

template template parameter,模版模版参数

template<typename T, 
    	template<typename T>
        	class Container
    	>
class XCls
{
private:
	Container<T> c;
};

template<typename T>
using Lst = list<T, allocator<T>>;

XCls<string, list>	mylst1;	// 不可行,因为list中还有第二甚至第三模版参数
XCls<string, Lst> 	mylst2;

C++11新特性

variadic template(since C++11),模版参数可变化

void print(){
    
}

template<typename T, typename...Types>
// 就是一个所谓的pack(包)
void print(const T& firstArg, const Types&... args){
    cout << firstArg << endl;
    cout << sizeof...(args) << endl;	// 求这个一包中有多少个参数
    print(args...);
}

auto (since C++11)

list<string> c;
auto ite = find(c.begin(), c.end(), target);
// => list<string>::iterator ite;

ranged-base for (since C++11)

for(auto elem : v){
	elem *= 3;	// pass by value 不会修改vector中的值
}

for(auto& elem : v){
    elem *= 3;	// pass by reference
}

Reference

  • 必须设初值,且一直代表该变量不能改变
  • 而指针可以变
  • 引用的sizeof和地址都与代表的对象相同(编译器制造出的假象)
int x = 0;
int* p = &x;	// 32位机器上指针为4字节
int& r = x;		// sizeof(r) == sizeof(x) &x == &r
int x2 = 5;

r = x2;			// r = x = 5
int& r2 = r;	// r2也代表x
  • 以下被视为“same signature”,所以二者不能同时存在
double imag(const double& im)
{
    ...
}

double imag(const double im)
{
    ...
}	// Ambiguity

const 是函数签名的一部分

object model 对象模型

关于vptr和vtbl(多态)

image.png

((p->vptr)[n]) § 或 (*p->vptr[n] ) § // p就是this指针
无需再判断指针是什么类型

动态绑定

  • 动态绑定的条件
    • 使用指针
    • 指针向上转型
    • 调用的是虚函数

谈谈const

  • 常量成员函数
    • 不能改变class都data
    • const object不可以调用non-const member function(不保证data members不变)

image.png

  • 标准库的字符串
    • 不加const考虑COW(copy on write),加const不考虑COW,因为它们是共享的
  • 当成员函数的const和non-const版本同时存在,const object只能调用const版本,non-const object只能调用non-const

new & delete

全局new & delete

重载 operator new、operator delete、operator new[] (数组)、operator delete[] (数组)

inline void* operator new(size_t size){
    return myAlloc(size);
}

inline void* operator new[](size_t size){
    return myAlloc(size);
}

inline void operator delete(void* ptr){
    return myFree(ptr);
}

inline void operator delete[](void* ptr){
    return myFree(ptr);
}

member operator new/delete

  • 接管以后做内存池
class Foo{
public:
	void* operator new(size_t);				// 传入一个对象的大小
	void operator delete(void*, size_t);	// 第二个参数可选

	void* operator new[](size_t);			// 会在数组前面加个counter记录数组大小
	void operator delete[](void*, size_t);
};

如果使用者想直接跳过成员函数中的new,可直接:

Foo* f = new Foo;
delete f;		// 若无成员函数,就调用全局的。	

Foo* f = ::new Foo;
::delete f;		// :: 直接调用全局

重载new(), delete(), Placement new

  • 重载class member operator new(),写出多个版本,前提是每个版本的声明都必须有独特的参数列,其中第一参数必须是size_t,其余参数以new所指定的placement arguments为初值。出现于new(…)内的就是placement arguments
  • 也可以重载class member operator delete(),写出多个版本,但他们绝不会被delete调用,只有当new所调用的ctor抛出exception,才会调用这些重载版的operator delete()。它只能看这样被调用,主要用来归还未能完全创建成功的object说占用的memory。
  • delete与new一一对应处理ctor报出的异常
Foo* pf = new(300, 'c') Foo;
Foo* pf2 = new(300, 'c')Foo(1);	//ctor的区别
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yyy_jin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值