conversion function
没有返回类型
class Fraction {
public:
// 要加const,分子和分母并不会改变
// 由于已经有了double(),虽然是返回double类型,但是可以不写
operator double() const {
return (double)(m_numerator/m_denominator);
}
private:
int m_numerator; // 分子
int m_denominator; // 分母
}
Fraction f(3,5);
double d = 4 + f;
non-explicit-one-argument ctor
public:
// 1个实参
Fraction(int num, int den = 1) : m_numerator(num), m_denominator(den) {}
Fraction operator + (const Fraction& f) {
return Fraction(...);
}
Fraction f(3,5);
Fraction d2 = f + 4; // 调用non-explicit ctor将4chang Fraction(4,1),然后调用operator +
当conversion function和non-explicit同时有的时候,Fraction d2 = f + 4;会报错!
编译器无法判断使用哪一个
当变成explicit Fraction():…,4就不会自动变成4/1
explicit 90%用到的时候是在构造函数前面
pointer-like classes
关于智能指针
-> 符号很特别,消耗过还会有
关于迭代器
需要写出++,–等指针可以移动
function-like classes
function template, 函数模板
Note: 不必说明类型,使用时候编译器会进行实参推导
member template, 成员模板
pair<Derived1, Derived2> p;
pair<Base1, Base2> p2(p);
// 上面相当于=>下式
// 把一个由鲫鱼和麻雀构成的pair,放进一个由鱼类和鸟类构成的pair
pair<Base1, Base2> p2(pair<Derived1, Derived2>());
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; }
};
cout << hash<long>()(1000);
partial specialization,模板偏特化
1.个数的偏特化
template <typename T, typename Alloc=...>
class Vector { ... };
template <typename Alloc=...> // T已绑定
class Vector<bool, Alloc> {};
2.范围的偏特化,类型变成指针
template <typename T>
class C { ... };
template <typename U>
class C<U*> { ... }; // 变成了指针
// 对应上面两个模板
C<string> obj1;
C<string *> obj2;
模板模板参数,template template parameter
template <typename T,
template <typename T>
class Container
>
class XCLs {
private:
Container<T> c;
public:
...
}
template <typename T>
using Lst = list<T, allocator<T>>;
XCLs<string, list> mylst1; // ERROR,容器是有第二模板参数的,有的有第三。。。
XCLs<string, Lst> mylst2; // RIGHT
下面这种情况不是template template parameter
template <class T, class Sequence = deque<T>>
class Stack {
protected:
Sequence c; // 底层容器
}
Stack<int> s1; // 有默认参数
Stack<int, list<int>> s2; // 已经绑定死了,没有模糊的东西
三主题之一:variadic template(since C++11), 数量不定的模板参数
void print() {}
template <typename T, typename... Types>
void print(const T& firstArg, const Types&... args) {
cout << firstArg << endl;
print(args...); // 递归调用,最后一次没有参数,调用上面的print()
}
print(7.5, "hello", bitset<16>(377), 41);
// sizeof...(args)返回参数个数
三主题之二:auto(since C++11)
list<string> c;
...
// 以前这种写法
list<string>::iterator ite;
ite = find(c.begin(), c.end(), target);
// 等价于下面
auto ite = find(c.begin(), c.end(), target);
// 但是下面这种写法是错误的
auto ite;
ite = find(c.begin(), c.end(), target);
三主题之三:ranged-base for(since C++11),新形式的for写法
pass by value和pass by reference
vector<double> vec;
...
for (auto elem : vec) {
cout << elem << endl; // 不会改变vector里的内容
}
for (auto& elem : vec) {
cout << elem *= 3; // 会改变vectoe里的内容
}
reference
对象和其reference的大小、地址都相同(全都是假象)
多用于参数传递,而不是声明变量
引用底层传递的其实是指针,速度比较快
// 两者不能同时存在,由于是same signature(不包含返回类型)
double imag(const double& im) { ... }
double imag(const double im) { ... } // 会有二义
const是函数签名的一部分,一个有const,一个没有const的是可以共存的
对象模型(Object Model):关于vptr和vtbl
只要有一个虚函数,就会有指针,不管有多少个,只会有一个vptr
父类有虚函数,子类也一定有
静态绑定会被编译器编译成call address
虚机制,也就是动态绑定的形式,根据指针来决定走的哪一条路
满足以下三个条件:
- 必须通过指针来调用
- 指针是向上转型upcasting,new的是pig,指的是animal
- 调用的是虚函数
走的是下图的路线,注意是A*,调用不同的虚函数来创建不同的形状
p就是this pointe
关于this
通过对象来调用一个函数,对象的地址就是this
下面的例子满足三个条件
谈谈const
const object是不能调用non-const member functions,编译器无法通过
const String str("hello world");
str.print(); // 设计print()的时候是必须加上const的
charT operator[] (size_type pos) const {
...... // 不必考虑COW
}
reference operator[] (size_type pos) {
...... // 必须考虑COW
}
COW: Copy On Write
new 和 delete
new array 前面有一个计数内存
重载new(), delete()
class member operator new ()可以有多个版本,前提就是每一个声明必须有独特的参数列,其中第一个参数必须是size_t。当出现new(…)小括号里面的就是placement arguments
Foo* pf = new (300, 'c')Foo;
// 一般的operator new()重载
void* operator new(size_t size) {
return malloc(size);
}
// 标准库提供的重载,只传回来pointer
void* operator new(size_t size, void* start) {
return start;
重载版本的class member operator delete()可以有多个版本,但是他们绝对不会被delete()调用,只有当new所调用的ctor抛出exception,才会调用哪个这些重载版的operator delete。它它只能这样被调用,主要用来归还未能完全创建成功的object所占用的memory。
即使operator delete() 未能一一对应operator new(),也不会报错,意思是,你放弃了处理ctor发出的异常。
basic_string使用new(extra)扩充申请量
Rep是用来的计数引用的