C++ 侯捷老师基础视频补充
01 convesion function,转换函数
- 转换函数只能转换为任意 type 只要前面出现过
- 不需要写返回类型
class Fraction
{
public:
Fraction(int num, int den = 1)
: m_numerator(num), m_denominator(den) { }
operator double() const
{
return (double)m_numerator / m_denominator;
}
private:
int m_numerator; // 分子
int m_denominator; // 分母
}
int main(void)
{
Fraction f(3, 5);
double d = 4 + f;
std::cout << "d = " << d << std::endl;
}
02 non-expicilt-one-argument ctor
- 编译器可以在适合的时候将别的类型转换为该 类的类型
- 构造函数不加 explicit 就是可以转换
- 构造函数加 explicit 就是不可以加
- 需要具体问题具体分析,到底是不是正确
class Fraction
{
public:
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(this->m_n() + f.m_n(),
this->m_d() + f.m_d());
}
void print()
{
std::cout << "分子 = " << m_numerator << std::endl;
std::cout << "分母 = " << m_denominator << std::endl;
}
int m_n() const
{
return m_numerator;
}
int m_d() const
{
return m_denominator;
}
private:
int m_numerator; // 分子
int m_denominator; // 分母
};
int main(void)
{
Fraction f(3, 5);
Fraction fr = f + 4;
fr.print();
return 0;
}
03 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 methon(void)
{
std::cout << "TEST" << std::end;
}
}
int main(void)
{
shared_ptr<Foo> sp(new Foo());
(*sp).methon();
sp->methon();
return 0;
}
04 pointer-like classes,关于迭代器
- ++ 操作符重载
- – 操作符重载
- == 操作符重载
- != 操作符重载
- * 操作符重载
- -> 操作符重载
05 function-like classes,仿函数
- () 操作符重载
- 类中有 () 符号重载
- 标准库中,仿函数会继承
06 member template 成员模板
- 让构造函数更有弹性
- 继承的类赋予给父类
Basel* ptr = new Derviedl; // up-cast
shared_ptr<Basel>sptr(new Derivedl); // 模拟 up-cast
template<typename T>
class A
{
public:
A(T n)
: num(n) { }
void print()
{
std::cout << "num = " << num << std::endl;
}
T num;
};
template<typename TT>
class B:public A<TT>
{
public:
template<typename TTT>
explicit B(TTT n)
: A<TT>(n) { }
};
int main(void)
{
// 输出 3
A<int> a(3);
a.print();
// 警告 输出 3
A<int> aa(3);
aa.print();
// 不会警告,输出 3
B<int>b(3.2);
b.print();
// 输出 3.2
B<float>c(3.2);
c.print();
return 0;
}
07 specialization,模板特化
template<typename T>
class A
{
public:
A(T n)
: num(n) { }
void print()
{
std::cout << "num = " << num << std::endl;
}
private:
T num;
};
template<>
class A<int>
{
public:
A(int n)
: num(n) { }
void print()
{
std::cout << "这是整个模板特化的 int 函数" << std::endl;
std::cout << "num = " << num << std::endl;
}
private:
int num;
};
int main(void)
{
A<int> a(3);
a.print();
A<float> b(3.2);
b.print();
return 0;
}
08 partial specialization,模板偏特化
- 个数上的偏
- 范围的偏
template<typename T, typename U>
class A
{
public:
A(T n, U d)
: num(n), data(d) { }
void print()
{
std::cout << "num = " << num << std::endl;
std::cout << "data = " << data << std::endl;
std::cout << std::endl;
}
private:
T num;
U data;
};
template<typename U>
class A<int, U>
{
public:
A(int n, U d)
: num(n), data(d) { }
void print()
{
std::cout << "这是模板偏特化的 pint 函数" << std::endl;
std::cout << "num = " << num << std::endl;
std::cout << "data = " << data << std::endl;
std::cout << std::endl;
}
private:
int num;
U data;
};
int main(void)
{
// 输出结果 3 3
A<int, int> a(3, 3);
a.print();
// 输出结果 3.2 3
A<float, int> b(3.2, 3);
b.print();
return 0;
}
template<typename T>
class A
{
public:
A(T n)
: num(n) { }
void print()
{
std::cout << "num = " << num << std::endl;
std::cout << std::endl;
}
private:
T num;
};
template<typename T>
class A<T*>
{
public:
A(T* pn)
: num(pn) { }
void print()
{
std::cout << "这是整个模板偏特化的 pint 函数" << std::endl;
std::cout << "num = " << num << std::endl;
std::cout << "*num = " << *num << std::endl;
}
private:
T* num;
};
int main(void)
{
// 输出结果 3.2
A<float> b(3.2);
b.print();
// 输出结果 内存地址 + 3.2
float f = 3.2;
A<float*> c(&f);
c.print();
return 0;
}
09 template template parameter,模板模板参数
template<typename T>
class A
{
public:
A(T n)
: num(n) { }
void print()
{
std::cout << "num = " << num << std::endl;
std::cout << std::endl;
}
private:
T num;
};
template<typename T,
template <typename U>
class C
>
class B
{
public:
B(T n)
: num(n) { }
void print()
{
std::cout << "这是 模板模板参数 的 print 函数" << std::endl;
std::cout << "num = " << num << std::endl;
a.print();
}
private:
T num;
// C<T> a(3.2); // 为什么这样的方式会报错
// 为什么 这样的方式就可以
C<T> a = C<T>(3.2);
};
int main(void)
{
// 编译会有警告,以为 上面 4 行是 浮点数,这里是整数类型
// 输出结果 3 3
B<int, A> b(3);
b.print();
// 输出结果 3.2 3.2
B<float, A> c(3.2);
c.print();
return 0;
}
10 关于 C++ 标准库
- Iterators 迭代器
- Contaliners 容器
- Functors 仿函数
- Algorithms 算法
- Sequence containers
- array
- verctor
- deque
- forward_list
- list
- Container adaptor
- stack
- queue
- priority_queue
- Associative containers
- set
- multiset
- map
- multimap
- Unordered associative con
- unordered_set
- unordered_multiset
- unordered_map
- unordered_multimap
- Sorting
- sort
- stable_sort
- partial_sort
- partial-sort——copyis-sorted
- is_sorted_until
- nth_element
- Binary search
- lower_bound
- upper_bound
- equal_range
- binary_search
- Merge
- merge
- inplace_merge
- includes
- set_union
- set_intersection
- set_difference
- set_symmetric_difference
注意:自己能将这些数据结构,函数,算法使用一次效果最好
11 variadic templates (since C++ 11)
- 想知道后面的参数有多少个
sizeof...(args)
- 在函数和类中都可以使用
...
就是一个所谓的 pack(包)- 用于 template parameters,就是 template parameters pack(模板参数包)
- 用于 function parameter types,就是 function parameter types pack(函数参数类型包)
- 用于 function parameters,就是 functionparameters pack(函数参数包)
#include <iostream>
#include <bitset>
void print()
{
}
template<typename T, typename... Types>
void print(const T& firstArg, const Types&... args)
{
std::cout << firstArg << std::endl;
print(args...);
}
int main(void)
{
print(7.5, "hello", std::bitset<16>(377), 42);
return 0;
}
12 auto (since C++11)
#include <iostream>
#include <list>
#include <string>
using namespace std;
int main(void)
{
list<string> c;
c.push_back("no one on");
c.push_back("This is str one.");
c.push_back("test tes three");
c.push_back("the end one");
c.sort();
// list<string>::iterator ite;
// for (ite = c.begin(); ite != c.end(); ite++)
for (auto ite = c.begin(); ite != c.end(); ite++)
{
cout << *ite << endl;
}
return 0;
}
13 ranged-base for (since C++11)
#include <iostream>
#include <list>
#include <string>
using namespace std;
int main(void)
{
list<string> c;
c.push_back("no one on");
c.push_back("This is str one.");
c.push_back("test tes three");
c.push_back("the end one");
c.sort();
for (auto& ite : c)
{
cout << ite << endl;
ite = "test";
}
cout << endl;
for (auto ite : c)
{
cout << ite << endl;
}
cout << endl;
for (auto i : {1, 2, 3, 4, 5})
{
cout << i << endl;
}
return 0;
}
14 reference
- object 和 reference 的大小相同,地址也相同
- 常见用途
- 多半用在传输传递上
- 以下被认为
same signature
所以不能同时存在
double imag(const double& im) { ... }
double imag(const double im) { ... } // Ambiguity
#include <iostream>
using namespace std;
int main(void)
{
int x = 0;
int *p = &x;
int& r = x;
int x2 = 5;
cout << "x = " << x << endl;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "r = " << r << endl;
cout << "x2 = " << x2 << endl;
cout << endl;
r = x2; // r 不能重新代表其他东西,现在 r x2 都是 5 了
cout << "r = " << r << endl;
cout << "x = " << x << endl;
cout << "x2 = " << x2 << endl;
return 0;
}
#include <iostream>
using namespace std;
typedef struct Stag
{
int a;
int b;
int c;
int d;
} S;
int main(void)
{
double x = 0;
double* p = &x; // p 指向 x, p 的值是 x 的地址
double& r = x; // r 代表 x,现在 r x 都是 0
// 64 位系统下测试
cout << sizeof(x) << endl; // 8
cout << sizeof(p) << endl; // 8
cout << sizeof(r) << endl; // 8
cout << p << endl; // 0x7ffe355f1920
cout << *p << endl; // 0
cout << x << endl; // 0
cout << r << endl; // 0
cout << &x << endl; // 0x7ffe355f1920
cout << &r << endl; // 0x7ffe355f1920
cout << endl;
S s;
S& rs = s;
cout << sizeof(s) << endl; // 16
cout << sizeof(rs) << endl; // 16
cout << &s << endl; // 0x7ffe355f1900
cout << &rs << endl; // 0x7ffe355f1900
return 0;
}
15 对象模型 (Object Model) : 关于 vptr 和 vtbl
- 多态 动态绑定 虚函数 是一回事
- 第一 通过指针调用
- 第二 向上转型
- 第三 调用虚函数
- 编译器编译为动态绑定
#include <iostream>
#include <list>
using namespace std;
class A
{
public:
virtual void print(void)
{
cout << "Test this is A virtual print." << endl;
}
};
class B: public A
{
public:
virtual void print(void)
{
cout << "Test this is B virtual print." << endl;
}
};
class C: public A
{
public:
virtual void print(void)
{
cout << "Test this is C virtual print." << endl;
}
};
class D: public B
{
public:
virtual void print(void)
{
cout << "Test this is D virtual print." << endl;
}
};
int main(void)
{
list<A*> lt;
A* a = new A();
B* b = new B();
C* c = new C();
D* d = new D();
lt.push_back(a);
lt.push_back(b);
lt.push_back(c);
lt.push_back(d);
for (auto ite = lt.begin(); ite != lt.end(); ite++)
{
// 多态 动态绑定 虚函数
(*ite)->print();
(*(*ite)).print();
}
delete a;
delete b;
delete c;
delete d;
return 0;
}
16 Object Model : 关于 this
- 通过一个对象调用一个函数,那个对象的地址就是 this
17 Object Model : 关于 Dynamic Binding
#include <iostream>
using namespace std;
class A
{
public:
virtual void print(void)
{
cout << "Test this is A virtual print." << endl;
}
};
class B: public A
{
public:
virtual void print(void)
{
cout << "Test this is B virtual print." << endl;
}
};
int main(void)
{
B b = B();
A a = (A)b;
b.print(); // B
a.print(); // A 因为 a 是一个对象
(&a)->print(); // A 因为 a 是一个对象
A* pa = &b;
pa->print(); // B 因为 pa 是一个指针
(*pa).print(); // B 因为 pa 是一个指针
pa = new B();
pa->print(); // B
(*pa).print(); // B
delete pa;
return 0;
}
18 重载 new / delete
- 重载全局的 ::operator new, ::operator delete, ::operator new[], ::operator delete[]
#include <iostream>
using namespace std;
void* operator new(size_t size)
{
cout << "Test void* operator new(size_t size) \n";
return malloc(size);
}
void* operator new[](size_t size)
{
cout << "Test void* operator new[](size_t size) \n";
return malloc(size);
}
void operator delete(void* ptr)
{
cout << "Test void operator delete(void* ptr) \n";
free(ptr);
}
void operator delete[](void* ptr)
{
cout << "Test void operator delete[](void* ptr) \n";
free(ptr);
}
int main(void)
{
int* pi = new int();
delete pi;
cout << endl;
int* pj = new int[3];
delete[] pj;
cout << endl;
int* pn = ::new int();
::delete pn;
return 0;
}
- 重载 member operator new / delete, new[] / delete[]
- 当成员 new delete 重载时可以通过 ::new ::delete 来调用全局的 new / delete
#include <iostream>
#include <string>
using namespace std;
class Foo
{
public:
int id;
long data;
string str;
Foo()
: id(0)
{
cout << "default ctor this = " << this << " id = " << id << endl;
}
Foo(int i)
: id(i)
{
cout << "ctor.this = " << this << " id = " << id << endl;
}
~Foo()
{
cout << "dtor.this = " << this << " id = " << id << endl;
}
virtual void print() { }
static void* operator new(size_t size);
// static void operator delete(void* pdead);
static void operator delete(void* pdead, size_t size);
static void* operator new[](size_t size);
// static void operator delete[](void* pdead);
static void operator delete[](void* pdead, size_t size);
};
void* Foo::operator new(size_t size)
{
Foo* p = (Foo*)malloc(size);
cout << "new size = " << size << endl;
return p;
}
void* Foo::operator new[](size_t size)
{
Foo* p = (Foo*)malloc(size);
cout << "new[] size = " << size << endl;
return p;
}
void Foo::operator delete(void* pdead, size_t size)
{
cout << "delete size = " << size << endl;
free(pdead);
}
void Foo::operator delete[](void* pdead, size_t size)
{
cout << "delete[] size = " << size << endl;
free(pdead);
}
int main(void)
{
Foo* pf = new Foo(7);
delete pf;
cout << endl;
Foo* pff = new Foo[5];
delete[] pff;
cout << endl;
Foo* pfn = ::new Foo(2);
::delete pfn;
return 0;
}
- 重载 palcement arguments new() delete()
- 第一个参数的 type 必须是 size_t
- 第一个参数默认传的就是穿件对象的 size 大小
- 可以写多个参数的 new()
- 也可写相对应的多个参数的 delete()
- 也可以不写,只有当 new() 所调用的构造函数发生异常的时候,才会调用相应的 delete()
- 重载 new() delete() 用来自己想多分配一些东西
#include <iostream>
#include <string>
using namespace std;
class Bad
{};
class Foo
{
public:
int id;
long data;
string str;
Foo()
: id(0)
{
cout << "default ctor this = " << this << " id = " << id << endl;
}
Foo(int i)
: id(i)
{
cout << "ctor.this = " << this << " id = " << id << endl;
throw Bad();
}
~Foo()
{
cout << "dtor.this = " << this << " id = " << id << endl;
}
virtual void print() { }
static void* operator new(size_t size);
static void* operator new(size_t size, void* start);
static void* operator new(size_t size, long extra);
static void* operator new(size_t size, long extra, char init);
// static void* operator new(long extra, size_t size);
// static void operator delete(void* pdead);
static void operator delete(void* pdead, size_t size);
static void operator delete(void* pdead, void* start);
static void operator delete(void* pdead, long extra);
static void operator delete(void* pdead, long extra, char init);
};
// 1
void* Foo::operator new(size_t size)
{
Foo* p = (Foo*)malloc(size);
cout << "new size = " << size << endl;
return p;
}
// 2
void* Foo::operator new(size_t size, void* start)
{
return start;
}
// 3
void* Foo::operator new(size_t size, long extra)
{
return malloc(size + extra);
}
// 4
void* Foo::operator new(size_t size, long extra, char init)
{
return malloc(size + extra);
}
// 5 第一个参数类型必须是 size_t 否则编译出错
// void* Foo:operator new(long extra, size_t size)
// {
// return malloc(extra + size);
// }
// 1
void Foo::operator delete(void* pdead, size_t size)
{
cout << "delete size = " << size << endl;
free(pdead);
}
// 2
void Foo::operator delete(void* pdead, void* start)
{
cout << "operator delete(void*, void*)" << endl;
}
// 3
void Foo::operator delete(void* pdead, long extra)
{
cout << "operator delete(void* pdead, long extra)" << endl;
}
// 4
void Foo::operator delete(void* pdead, long extra, char init)
{
cout << "operator delete(void* pdead, long extra, char init)" << endl;
}
int main(void)
{
Foo start;
Foo* p1 = new Foo;
cout << endl;
Foo* p2 = new (&start)Foo;
cout << endl;
Foo* p3 = new (100)Foo;
cout << endl;
Foo* p4 = new (100, 'A')Foo;
cout << endl;
// Foo* p5 = new Foo(1);
// cout << endl;
// Foo* p6 = new (&start)Foo(2);
// cout << endl;
// Foo* p7 = new (100)Foo(3);
// cout << endl;
Foo* p8 = new (100, 'A')Foo(4);
delete p1;
delete p2;
delete p3;
delete p4;
return 0;
}
// 测试结果,自己的使用的 clang 编译器没显示调用 delete()