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(多态)
((p->vptr)[n]) § 或 (*p->vptr[n] ) § // p就是this指针
无需再判断指针是什么类型
动态绑定
- 动态绑定的条件
- 使用指针
- 指针向上转型
- 调用的是虚函数
谈谈const
- 常量成员函数
- 不能改变class都data
- const object不可以调用non-const member function(不保证data members不变)
- 标准库的字符串
- 不加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的区别