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 类型
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
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, 可区分 重载函数
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 => 静 -> 动 态绑定
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 固定的 函数地址
(2) 动态绑定
( 必须 通过 ptr / ref 调 vf ): 运行时, 才能 通过 &obj -> vptr -> vtbl -> call 的 vf pointer
`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
网友评论