美文网首页
侯捷 视频下: 对象模型

侯捷 视频下: 对象模型

作者: my_passion | 来源:发表于2020-06-26 10:14 被阅读0次
vs 下 C++ code 反汇编

debug -> 窗口 -> 反汇编

单步调试过程中 就能在 `反汇编窗口` 
看 汇编代码执行过程

1 class 对象 隐式转换为 某类型 的 值: class 内含 conversion function

Fraction ( 分数 ) 对象 转换成 double

operator return_type/dst_type(para list) / operator double()

1) operator 前 不用再写 return type

2) 无参

3) 通常为 const

class Fraction
{
private:
    int numerator;
    int denominator;
public:
    //conversion function
    operator double() const
    {
        return (double)( numerator /  denominator );
    }
};

Fraction f(3, 5);

// 调 operator double() 把 f 转换为 3/5=0.6
double d = 4 + f; 

2 某类型 的 value 隐式转换为 类的对象: (non-)explicit single argument ctor

1. non-explicit: 不用 keyword explicit 修饰

single argument ( 只要 1 个 实参 就够了, 可以有 other 默认值 para)

class Fraction
{
private:
    int numerator;
    int denominator;
public:
    Fraction(int n1, int n2 = 1) : numerator(n1), denominator(n2){ }
    
    Fraction operator + (const Fraction& f)
    {
        return Fraction(...);
    }
};

Fraction f(3, 5);

// 先调 non-explicit single arg ctor 把 4 转换为 Fraction(4, 1).
// 再调 operator +
double d = f + 4; 

2. conversion function 与 non-explicit single argument ctor 同时存在 => 编译器 发现有 2条路 可走, 报错 ambiguous

`solu:`

single argument ctor 前 use

explicit: 修饰 ctor, 告诉 compiler 只有 构造对象 时, 才能 调 ctor

3 pointer-like class: smart pointer

#include <iostream>

class Foo
{
public:
    void method(){ std::cout << "Foo..." << std::endl; }
};

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

int main()
{
    shared_ptr<Foo> sp(new Foo);

    //1. -> 作用下去得到的 结果, 继续用 -> 作用
    sp->method(); // <=> pt->method();

    //2. call implicitly copy ctor
    Foo foo(*sp); // Foo foo; // ok as well
    foo.method();
}
shared_ptr.jpg

4 function like classes: Functor

重载函数调用操作符 ()class

Functor object仿函数 对象

`最佳实践:`

Functor/A is a type => 其 临时对象 A() 某些场景下 会被 compiler 解释为 func declaration => 最好用 A{}

#include<iostream>

template < typename T>
class A
{
public:
    const T& operator() (const T& x) { return x; }
};

int main()
{
    int a = 3;
    int b = 0;

    // 第 1 / 2 个 () 是 创建 临时对象 / 调 operator()
    b = A<int>()(a);
}

5 namespace

1. 功能 近似 java 中 

package

防止 `命名冲突`
namespace.jpg
2. 3 种 用法

(1) using namespace: using namespace std;

(2) using namespace 中 某 对象: using std::cout;

(3) 不 using, 直接用全名: std::cout
    最靠谱

6 class template

class 内 可以抽出来, 允许 user 任意指定类型 T: 告诉 compiler T 将来用时再 指定

template<typename T>
class complex
{                 
public:
    complex (T r = 0, T i = 0) 
        : re (r), im (i)                
    { }
};

complex<int> c2(1, 2);

7 function template

与 class template 区别:

模板实参推导 (argument deduction)

=> `抽象类型 T 的 具体类型`
=>

<> 中不必 ( 但 可以 ) 指定 T 类型

9.jpg

8 member template

class/struct template 里的 member 又是 template

`标准库 ctor 中用`

std::pair / std::shared_ptr泛化 copy ctor / ctor

pair<Base1, Base2> p1( pair<Derived1, Derived2>() );

shared_ptr<Base> spBase( new Derived );

// eg1
#include <iostream>

class Base
{
public:
    int x;
    
    Base() : x(0) {}
};

class Derived: public Base
{
public:
    int y;

    Derived(): Base(), y(1) {}
};

template<typename T>
struct A // note: struct
{
    T first;

    A() : first( T() ) {  }
    A(const T& _first) : first(_first) { }

    // 截取 U 中 前 sizeof(T) 部分 赋给 新对象 成员 t
    template <typename U>
    A(const A<U>& rhs) : first(rhs.first) { }
};

int main()
{
    A<Derived> a1;

    // (1) prob:
    // 因 A<Derived> is a type
    // => compiler 把 临时对象定义 A<Derived>() 当成了 函数声明
    // A<Base> a2( A<Derived>() );

    // (2) soultion: 临时对象定义 中 () 改用 {}
    A<Base> a2( A<Derived>{} );

    // <=>
    // A<Base> a2(a1);
}
// eg2
member template1.jpg member template2.jpg
反之, 不行
template <class T1, class T2>
struct pair
{
    T1 first;
    T2 second;

    template <class U1, class U2>
    pair(const pair< U1, U2>& p)
        : first(p.first), second(p.second) { }
        
    pair() : first( T1() ), second( T2() ) {}
    pair(const T1& t1, const T2& t2) 
        : first(t1), second(t2) {}
};
// eg3.
// 模拟 up-cast
shared_ptr<Base> sh_ptr(new Derived);
member template3.jpg

9 ( full ) specialization 特化

`1. 从泛化 到 特化`

1) template para list 去欲特化类型

2) <special_type> 放 class name 后

// 泛化
temlpate < class key> // 1) 去 special type Key 的 declaration
struct hash
{
};

// 特化
template <>
struct hash < long > // 2) special_type 放 class name 后 <> 
{
    size_t operator() (long x) const 
    {
        return x;
    }
 };

// `hash<long> ()  是 临时对象`
cout << hash<long>()(1000);

10 partial specialization 偏特化

1. 个数上偏

template < 只放 未绑定类型 >
class name < 放所有类型: 无论绑定与否 >

`只能 从左边开始 连续绑定若干个`
eg. 
2个 template para 绑定 第1个的 type
// 2个 模板参数
template < typename T, typename Alloc = ...> 
class vector
{
...
};
template < typename Alloc = ...>
class vector<bool, Alloc> // 绑定 第1个 type 为 bool
{
...
};

2. 范围上偏

泛化 -> 特化: template para 为 

任意 type T -> 范围缩小为 指针 T*: 可 指向 任意类型

`形式:`

template < 原类型 T 保留 >
class name < 范围上偏的类型 >

`note:`

特化 中 T* 与 泛化 中 T 这 2 个 T 可以 不同, 实际上 特化中 写为 U* 更清晰

// generalization
template < typename T>
class C
{
    // ...
};

// scope specialization
template < typename T>
class C<T*>
{
    // ...
};

// <=>
template < typename U>
class C<U*>
{
    // ...
};
C<string> obj1;  // 用 泛化
C<string*> obj2; // 用 特化

11 template template parameter 模板模板参数

作为 template para, 本身 也是 template

1. 例

(1) 第 1 / 2 template para 指定 容器元素类型 / 容器

#include <string>
#include <list>

//(1) class template
// 若 第 2 template para 要 用 template, 
// 则 必须用 第 1 template para 指定 第 2 template para
// 的 template para type
template < typename T,
           template < typename T>
               class Container >
class A
{
private:
    Container <T> c;
};

//(2) 用 using 定义 template template para 别名
template <typename T>
using lst = std::list<T, std::allocator<T> >;

int main()
{
    //(3) use 时, 只需 specify 第 1 template para, 
    // 第 2 template para 用 别名 即可, 
    // 不用 explicitly 指定 其 template para
    A<std::string, lst> a;
}

(2) 第 1/2 template para 指定 SmartPtr 所指 type / SmartPtr name

#include <string>
#include <list>
#include <memory> // shared_ptr

//(1) class template
template < typename T,
           template < typename T>
           class SmartPtr >
class A
{
private:
    SmartPtr<T> sp;
public:
    A(): sp(new T) { }
};

int main()
{
    //(2) use
    A< std::string, std::shared_ptr > a;
}

3. like but not template template parameter: Stack<int, std::list<int> >

std::list<int> 不再 模糊 => 不是 template

#include <list>
#include <deque>

template <class T, class Sequence = std::deque<T> >
class Stack
{
protected:
    Sequence c;
};

int main()
{
    Stack <int> s1;
    Stack <int, std::list<int> > s2;
}

12 variadic template / auto / ranged-base for

`C++11`
1. variadic template

template para 个数 可变

viod print() //最后1次调用,无参数,调该函数
{
}

template <typename T, typename... Types>
void print(const T& firstArg, const Types&... agrs)
{
    cout << firstArg << endl;
    print(args...); // 递归方式
}

print(7.5, "hello", bitset<16>(10) )

... 是所谓的 pack
sizeof...(args) 为 args 的数量

上例是 递归, variadic tempaltes 也可 继承/组合
2. auto
list <string> c;
// ...
list<string>::iterator ite;
ite = find(c.begin, c.end(), target)
list <string> c;
// ...

// 由 find 的 return type 就能 推出 ite 的 type
auto ite = find(c.begin, c.end(), target)
3. ranged-base for
for( declaration : collection )
{
    statement
}
// eg1. 
for ( int i : {1, 3, 5 } )
{
    cout << i << endl;
}
eg2.

pass by value: vec 中 每个元素 copy 到 elem

image.png

13 reference

`1. 逻辑上 引用 r 代表 x: x 是什么 r 就是什么`

(1) 引用 必须有 初值

(2) 引用 初始化后 不能再 变 / 改指

int& r = x; r = x2; <=> x = x2; 不是 r 改指 x2, 而是 对 r 最初所指的 x 调 operator=: 以 x2 为 arg

int x = 0;
inr& r = x;
int x2 = 5;
r = x2; // <=> r 所指 x = x2
reference1.jpg reference2.jpg
reference 是 1 种 beautiful pointer
引用 底层 实际上是 pointer

(2)
传 pointer: C 风格
传 object: copy arg

传 reference: C++ 中 更安全 和 自然, java 中 object 都是 reference

ref 多半参数传递返回类型

imag(1.0)  编译器不知道调 哪个

const 修饰 function, 可区分 重载函数

reference3.jpg

2. reference 作 para

(1) 传 ref to non-ptr / ptr: 交换2个 non-ptr/ptr

void swap(int &v1, int &v2)
{
    int temp = v2;
    v2 = v1;
    v1 = temp;
}

int a = 1;
int b = 2;
swap(a, b);
// para type: reference to pointer
void swapPtr(int* &v1, int* &v2)
{
    int *temp = v2;
    v2 = v1;
    v1 = temp;
}

int a = 1;
int b = 2;
int* p1 = &a;
int* p2 = &b;

swap(p1, p2);

(2) ref para 可在 return type 之外多1个 return value

(3) 传 ref ( 避免 copy 实参 ) + 无需修改 ( => 用 const ref )

3. reference 作 return type

(1) return ref: return 对象本身 ( 避免 copy return value )

return 的是 左值 => 可以被修改

(2) 不能 return reference to local obj
函数执行完, 会释放 local obj 的 存储空间, 
此时 reference to local obj 指向 undefined memory

14 Composition & Inheritance 下的构造和析构

https://www.jianshu.com/p/0f209eb83f47

15 对象模型 之 vptr vtbl

https://www.jianshu.com/p/eb69e02766e7

继承:
内存角度看: 继承数据, 继承内存

`函数角度看: 

继承函数 的 调用权

16 对象模型 之 this

1. 通过 obj 调 mem func, &obj 作 arg 传给 para this

2. Template Method example 中 myDoc.OnFileOpen() 同时引发 静 / 动态绑定

myDoc.OnFileOpen(): 通过 obj 调 non-vf / myDoc.OnFileOpen() -> 又调 this->Serialize(): 通过 poiner 调 vf => 静 -> 动 态绑定

this_1.jpg this_2.jpg

17 动/静 态绑定 本质区别

// 1. eg1: 动/静态绑定 本质区别

#include <iostream>
using namespace std;

class A
{
public:
    virtual void vf1(){ cout << "A:: virtual vf1() " << endl;}
};

class B: public A
{
public:
    virtual void vf1(){ cout << "B:: virtual vf1() " << endl; }
};

int main()
{
    A a;
    a.vf1();

    B b;
    b.vf1();

    A* pA = &b;
    pA->vf1();

    B* pB = &b;
    pB->vf1();
}

(1) 静态绑定 ( 通过 obj 调 vf / non-vf ): 直接把 相应 statement 编译成地址, 调用时 直接 call 固定的 函数地址

image.png

(2) 动态绑定 ( 必须 通过 ptr / ref 调 vf ): 运行时, 才能 通过 &obj -> vptr -> vtbl -> call 的 vf pointer

image.png image.png image.png
`Template Method:`
this_1.jpg image.png image.png image.png
myDoc.OnFileOpen(): 
通过 obj 调 non-vf => 静态绑定
image.png
this->Serialize(): 
通过 父类 ptr 调 子类对象 vf => 动态绑定
image.png

18 const

1. const obj 只能调 / 不能调 const / non-const mem func

non-const obj 能调 const 和 non-const mem func
image.png
const string cst_str("hello");

// 若 string::print_noncstr() 非 const => 调用报错
cst_str.print_noncst();

2. const obj / 字面值 / 右值表达式 不能初始化 non-const ref para

=> `ref para 大多都是 const ref`
, 因为 reference 大多 不会被修改
#include <iostream>

class A
{
private:
    int x;
public:
    void func(int& x_) {
        // x = x_;
    }
};

int main()
{
    A a;
    const int x = 1;

    a.func(x); // 无法将 const int 转换为 int&
    a.func(1); // non-const ref 初值 必须为 lvalue
}

3. mem func 的 const / non-const 版本 同时存在 时, const / non-const object 只能调 const / non-const 版本

4. const mem func: const 把 this 的 类型 从 const pointer 变为 const pointer to const classType

const classType * const this
=> 

1) const 修饰 mem func, 可区分 overloaded function

2) this 本身 及 this 所指 obj( 的 immutable mem data) 均 不可改变
note:

return type 不属于 func signature => 不可区分 overloaded func

相关文章

网友评论

      本文标题:侯捷 视频下: 对象模型

      本文链接:https://www.haomeiwen.com/subject/drmyfktx.html