还没有整理过的笔记,有点乱
C++ 程序设计II 兼谈对象模型
Conversion function - 转换函数 operator type()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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_denominator; int m_numerator; };
int main() { Fraction f(3,5); double d = 4 + f; cout << d << endl; }
|
non-explicit-one-argument ctor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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_denominator; int m_numerator; };
int main() { Fraction f(3,5); Fraction d = 4 + f; }
|
explicit-one-argument ctor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Fraction { public: explicit Fraction(int num, int den = 1) : m_numerator(num), m_denominator(den) {} Fraction operator+(const Fraction& f) { return Fraction(...); } operator double() const { return ((double)m_numerator / m_denominator); } */ private: int m_denominator; int m_numerator; };
int main() { Fraction f(3,5); Fraction d = 4 + f; }
|
应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| template<class Alloc> class vector<bool, Alloc> { public: typedef __bit_reference reference; protected: reference operator[](size_type n) { return *(begin() + defference_type(n)); } } struct __bit_reference { unsigned int* p; unsigned int mask; ... public: operator bool() { return !(!(*p & mask)); } ... }
|
pointer-like classes, 关于智能指针
一个 class 产生出来的对象像一个指针(do more then pointer, such as auto pointer)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| template<class T> class shared_ptr { public: T& operator*() const { return *px;} T* operator->() const { return px;}
shared_ptr(T* p) : px(px) {}
private: T* px; long* pn; ... };
struct Foo { void method() {} }; int main() { shared_ptr<Foo> sp(new Foo); Foo f(*sp); sp -> method(); }
|
pointer-like classes, 关于迭代器(一种特别的智能指针)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| template<class T> class __list_node { void* prev; void* next; T data; }
template<lass T, class Ref, class Ptr> struct __list_iterator { typedef __list_iterator<T, Ref, Ptr> self; typedef Ptr pointer; typedef Ref reference; typedef __list_node<T>* link_type; link_type node; bool operator==(const self& x) const {return node == x.node;} bool operator!=(const self& x) const {return node != x.node;} reference operator*() const {return (*node).data;} pointer operator->() const {return &(operator*());}
self& operator++() {node = (link_type)((*node).next); return *this;} self operator++(int) {self tmp = *this; ++*this; return tmp;} self& operator--() {node = (link_type)((*node).prev); return *this;} self operator--(int) {self tmp = *this; --*this; return tmp;} };
int main() { list<Foo>::iterator it; *it; it -> method(); }
|
function-like classes, 所谓 仿函数 (像函数的类)
() 函数调用操作符 function call
一般只要看到class内重载了()操作符,那他的用意就是想要变成一个function,其构造的对象称为函数对象
标准库中,仿函数会继承一些奇特的基类如:unary_function , binary_function
1 2 3 4 5 6
| template<class Arg, class Result> struct unary_function { typedef Arg argument_type; typedef Result result_type; };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| template<class T> struct identity : public unary_function<T, T>{ const T& operator() (const T& x) const {return x;} };
template<class Pair> struct select1st : public unary_function<Pair, typname Pair::first_type> { const typename Pair::first_type& operator() (const Pair& x) const {return x.first;} };
template<class Pair> struct select2nd : public unary_function<Pair, typname Pair::second_type> { const typename Pair::second_type& operator() (const Pair& x) const {return x.second;} };
template<class T1, class T2> struct pair { T1 first; T2 second; pair() : first(T1()), second(T2()) {} pair(const T1& a, const T2& b) : first(a), second(b) {} };
int main() { pair<char,int> p('a',97); char ch = select1st(p); int in = select2nd(p); }
|
namespase 经验谈
避免命名冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| using namespace std;
#include <iostream> #include <memory>
namespace jj01 { void test_member_template() { ... } }
#include <iostream> #include <list> namespase jj02 { template<typename T> using Lst = list<T,allocator<T>>; void test_template_param() {...} }
int main(int argc, char** argv) { jj01::test_member_template(); jj02::test_template_param(); }
|
class template, 模板类(泛型编程)
1 2 3 4 5 6
| template<class T> class Class { T a; public: T getA() const { return a;} };
|
function template, 函数模板
编译器会对 function template 进行 实参推导 (augument deduction)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class stone { public: stone (int w, int h, int we) : _w(w), _h(h), _weight(we) {} bool operator< (const stone& ths) const {return _weight < rhs._weight;} private: int _w, _h, _weight; };
template<class T> inline const T& min(const T& a, const T& b) { return b < a ? b : a; }
|
member template, 成员模板(令构造函数更有弹性)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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) {}
template<class U1, class U2> pair(const pair<U1, U2>& p) : first(p.first), second(p.second) {} };
|
例子:
1 2 3 4 5 6 7 8 9 10 11
| class Base1 {}; class Derived1 {};
class Base2 {}; class Derived2 {};
pair<Derived1, Derived2> p; pair<Base1, Base2> p2(p);
pair<Base1, Base2> b; pair<Derived1, Derived2> b2(b);
|
1 2 3 4 5 6 7 8 9
| template<typename _Tp> class shared_ptr : public __shared_ptr<_Tp> { template<typename _Tp> explicit shared_ptr(_Tp1* __p) : __shared_ptr<_Tp>(__p) {} };
Base1* ptr = new Derived1; shared_ptr<Base1> sptr(new Derived1);
|
specialization, 模板特化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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;} }
int main() { cout << hash<int> () (1000); }
|
partial specialization, 模板偏特化 — 个数上的偏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| template <typename T, typename Alloc = ...> class vector { pass };
template <typename T, typename Alloc=...> class vector<bool, Alloc> { pass };
template <typename T> class C { pass };
template <typename T> class C<T*> { pass };
C<string> obj1; C<string*> obj2;
|
template template parameter, 模板模板参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| template <typename T, template<typename T> class Container > class XCls { private: Container<T> c; public: pass };
template <typename T> using Lst = list<T, allocator<T>>;
XCls<string, list> my1st1; XCls<string, Lst> my1st2;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| template<typename T, template<typename T> class SmatPtr> class XCls { private: SmatPtr<T> sp; public: XCls() : sp(new T) {} };
XCls<string, shared_ptr> p1; XCls<string, unique_ptr> p2; XCls<string, weak_ptr> p3; XCls<string, auto_ptr> p4;
|
这个不是 template template parameter
1 2 3 4 5 6 7 8 9
| template<typename T, class Sequence = deque<T>> class stack { pass protected: Sequence c; }
stack<int> s1; stack<int, list<int> > s2;
|
关于 C++ 标准库
Iterator 迭代器
Container 容器
Algorithm 算法
Functors 仿函数
查看标准库,并实验每一个已经实现的标准库功能。
C++11 新特性
variadic templates 数量不定的模板参数 (since C++11)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| template <typename T, typename... Types> void print (const T& firstArg, const Types&... args) { cout << firstArg << endl; print(args...); }
print(7.5, "hello", bitset<16>(337), 42);
|
auto 语法糖(since c++11)
1 2 3 4 5
| list<string> c; auto ite = find(c.begin(), c.end(), target);
auto it; it = find(c.begin(), c.end(),target);
|
range-base for 语法糖(since C++11)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| for(auto i : container) { statement } for(auto &i : container) { statement }
for(int i : {0,1,2,3,4,5,6,7,8,9}) { cout << i << endl; }
|
reference 引用(代表),实际上是指针实现的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int x = 0; int* p = &x; int& r = x; int x2 = 5;
cout << (sizeof(r) == sizeof(x)) << endl; cout << (&r == &x) << endl;
r = x2; int& r2 = r;
|
reference 通常不用于声明变量,而用于参数类型(parameter type)和返回类型(return type)的描述.
1 2 3 4 5 6 7 8 9 10 11 12
| void func1(T *pobj) {pobj -> xxx();} void func2(T pobj) {pobj.xxx();} void func3(T& pobj) {pobj.xxx();}
T obj; func1(&obj); func2(obj); func3(obj);
double imag(const double& im); double imag(const double im);
|
Q : const 是不是函数签名的一部分,即是否能作为重载的指标?
A : 是!
Object Model 对象模型
Part I 的承接
Inheritance 继承: 构造由内而外,析构由外而内
Composition 复合: 构造由内而外,析构由外而内
Inheritance+Composition: 构造由内而外,析构由外而内
Derived::Derived(…) : Base(),Component() {…}
Derived::~Derived() {… Component(); Base()} // 与构造相反
关于 vptr 和 vtbl (虚指针和虚表)
只要类中有虚函数,其对象在内存中就会多一根指针(指向虚表)
父类有虚函数,子类对象也一定拥有该指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class A { public: virtual void vfunc1(); virtual void vfunc2(); void func1(); void func2(); private: int m_data1, m_data2; }; class B : public A { public: virtual void vfunc1(); void func2(); private: int m_data3; }; class C : public B { public: virtual void vfunc1(); void func2(); private: int m_data1, m_data4; };
|
内存模型: 动态绑定
1 2 3 4 5
| C *p = new C; (*p).vfunc2();
(*(p->vptr)[n])(p); (* p->vptr[n] )(p);
|
应用:PPT 图形类(多态的应用)
总结:
C++ 编译器看到一个函数调用,会有两个考量(静态绑定,动态绑定)
- 静态绑定是被编译成: CALL xxxx(func address)。
- 但如果符合某些条件就会动态绑定:
- 通过指针调用
- 指针向上转型 up-cast
- 所调用的是虚函数(virtual func)
动态绑定的形式:虚机制
多态:指针具有很多的类型(型态)
关于 this pointer
设计分析继承体系时要对this pointer有一个清晰的认识
对象调用成员函数时,该对象的this指正就会隐含地传入函数中
下图中在对象调用OnFileOpen()时传入对象地址this,因此碰到虚函数Serialize()函数后,回去寻找CMyDoc类的虚函数表中的函数(动态绑定)
谈谈 const (const member function 常量成员函数)
const 是属于函数签名的一部分
1 2 3 4 5 6 7 8
| class Class { public: Class() {} int function() const {return mem;} int function() {return mem;} private: int mem; };
|
|
const object(datamember不可变动) |
non-const object(datamem可变动) |
const member functions(保证datamenber不变) |
YES |
YES |
non-const member functions(不保证datamember不变) |
无法调用 |
YES |
当成员函数的 const 和 non-const 版本同时存在时,const Object 只会调用 const 版本,non-const Object 只会调用 non-const 版本
关于 new , delete. array new , array delete.(重载)
Part I 承接:
全局重载形式
成员重载形式
new 分解为 3 个动作
delete 分解为 2 个动作
接管内存的分配和释放的行为
示例, 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #ifndef __FOO__ #define __FOO__
#include <iostream> #include <string>
class Foo { public: int _id; long _data; string _str;
public: Foo() : _id(0) {std::cout << "default ctor. this = " << this << "id = " << _id << std::endl;} Foo(int id) : _id(id) {cout << "ctor. this = " << this << "id = " << _id << std::endl;}
~Foo() {std::cout << "dtor. this = " << this << "id = " << _id << std::endl;}
static void* operator new(size_t size); static void* operator delete(void* phead, size_t size); static void* operator new[](size_t size); static void* operator delete[](void* phead, size_t size); };
void* Foo::operator new(size_t size) { Foo* p = (Foo*) malloc(size); std::cout << "Foo:new has been called." << std::endl; return p; }
void* Foo::operator delete(void* phead,size_t size) { std::cout << "Foo:delete has been called." << std::endl; free(phead); }
void* Foo::operator new[](size_t size) { Foo* p = (Foo*) malloc(size); std::cout << "Foo:new[] has been called." << std::endl; return p; }
void Foo::operator delete[](void* phead, size_t size) { std::cout << "Foo:delete[] has been called." << std::endl; free(phead); }
#endif
|
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <iostream> #include "Foo.h"
using namespace std;
int main() { cout << "sizeof(Foo) = " << sizeof(Foo) << endl;
Foo *p = new Foo(7); delete p;
cout << "============================================" << endl;
Foo* pArray = new Foo[5]; delete[] pArray;
cout << "********************************************" << endl;
Foo* _p = ::new Foo(7); ::delete[] _p;
cout << "============================================" << endl;
Foo *_pArray = new Foo[5]; ::delete[] _pArray;
return 0; }
|