侯捷cpp-oop(下) 笔记

Table of contents
- C++程序设计兼谈对象模型-导读
- conversion function, 转换函数
- non-explicit-one-argument ctor
- pointer-like classes
- function-like classes, 所谓仿函数
- member function, 成员模版
- specialization, 模版特化
- partial specialization 模版偏特化
- 模版模版参数 template template parameter
- 关于 C++ 标准库
- 三个主题
- Reference
- 复合&继承关系下的构造和析构
- 关于 vptr 和 vtbl
- 关于 this
- 关于动态绑定
- 谈谈 const
- 关于 new, delete
- 重载 operator new, operator delete
- 示例
- 重载 new(), delete() -- placement new/delete ()
- Basic_String 使用 new(extra) 扩充申请量

C++程序设计兼谈对象模型-导读
conversion function, 转换函数
class Fraction {
public:
Fraction(int num, int den=1) : m_numerator(num), m_denominator(den){};
operator double() const {
return 1.0 * m_numerator / m_denominator;
}
private:
int m_numerator;
int m_denominator;
};
转换函数没有返回值
函数名为
operator double
no parameters
转换这个语义本身不改变成员变量,因此需要加
const
修饰。虽然不加const
也可以通过编译。
non-explicit-one-argument ctor
Fraction(int num, int den=1)
这个ctor,是2 parameters, 1 argument
. 只需要一个 argument(实参)
就可以实例化。
class Fraction {
public:
Fraction(int num, int den=1) : m_numerator(num), m_denominator(den){};
Fraction operator+ (const Fraction& f) {
return Fraction(0, 0); // ignore reality.
}
private:
int m_numerator;
int m_denominator;
};
int main() {
Fraction f(3, 5);
Fraction d2 = f + 4;
return 0;
}
f + 4
, 会查找到 Fraction operator+ (const Fraction& f)
这个函数.
然后会尝试调用non-explict ctor
把 4
转化为 Fraction
类型, 再传递进入 operator+
.
explict
explict
会告诉编译器不要进行隐式转换, 可以用来修饰ctor
和conversion function
. 如果需要进行转换,需要在调用处显式指出
。
修饰 conversion function
这一点大部分资料不会指出,但其实是可行的. 可以参考 user-defined conversion function .
pointer-like classes
关于智能指针
一般pointer
能做的事情,pointer-like classes
也可以做。因此能应用到 pointer
上的运算符,也可以应用到 pointer-like classes
, 如operator*()
、 opreator->()
.
对于 sp->method()
, 操作符 ->
会作用在 sp
上, 调用 T* shared_ptr::operator->()const
.
调用后,如果 ->
是一般的操作符,如*
, 会被消耗, 变为 px method()
.
但是 ->
有一个特性,会在有操作数存在的情况下,一直存在,因此经过一次调用后不会被消耗,仍然是 px->method()
.
关于迭代器
迭代器也是一类pointer-like class
, 使用者调用 *
意图获得 data
本身; 使用者调用 ->
, 意图获得 data
的地址,并且在改地址上继续复用 ->
来进行一系列操作。
function-like classes, 所谓仿函数
operator()
也叫 function call operator.
只要 class
内部重载了 operator()
那么就可以称为 functor(仿函数)
.
标准库中仿函数的奇特模样
unary_function
和 binary_function
既没有成员变量,也没有成员函数,理论上实际的大小是 0
.
至于为什么要有 c++ 基本概念之 functor 这篇文章讲的不错。
member function, 成员模版
这样做可以让ctor
更有 "弹性", 可以接收多种类型的参数。
specialization, 模版特化
泛化
和特化
互为相反。
#include <iostream>
template <typename Key>
class hash {};
template<>
class hash<char> { // 格式类似于这种, 把上面的不确定的 typename 拿下来, 变为确定的类型.
public:
size_t operator() (char ch) {
return size_t(ch);
}
};
template<>
class hash<long> {
public:
size_t operator() (long l) {
return size_t(l);
}
};
int main() {
hash<long>()(1l);
hash<char>()('a'); // 第一个() 构造出一个匿名对象, 第二个() 调用重载后的小括号运算符.
return 0;
}
特化
也叫 全特化(full specialization)
, 也有 partial specialization
.
partial specialization 模版偏特化
函数模版只能全特化, 而类模版可以偏特化和全特化。
特化必须在同一个命名空间下进行,但 std
是一个例外,用户可以特化其中的模版,但不可以添加模版。
个数的偏
偏特化的顺序只能从左向右绑定模版参数
.
template <typename T1, typename T2>
struct PPair {
int hash() {
std::cout << "in general hash() " << std::endl;
}
};
template <typename T2>
struct PPair<int, T2> {
int hash() {
std::cout << "in <int, T2> partial hash()" << std::endl;
}
};
int main() {
PPair<double, float>().hash();
PPair<int, double>().hash();
return 0;
}
in general hash()
in <int, T2> partial hash()
范围的偏
template<typename T>
struct JoJo {
void stand() {
std::cout << "in general stand()" << std::endl;
}
};
template<typename U>
struct JoJo<U*> {
void stand() {
std::cout << "in U* type stand()" << std::endl;
}
};
int main() {
JoJo<double>().stand();
JoJo<double*>().stand();
JoJo<int*>().stand();
return 0;
}
in general stand()
in U* type stand()
in U* type stand()
模版模版参数 template template parameter
关于 C++ 标准库
查看 C++ 版本
std::cout << __cplusplus << std::endl;
三个主题
variadic templatem, 数量不定的模版参数
关键字 typename...
可以使用 sizeof...(args)
来获取剩余的参数数量。
void print() {}
template<typename T, typename... TS>
void print(const T& firstArg, const TS&... args) {
cout << firstArg << "\t rest number of TS is " << sizeof...(args) << endl;
print(args...);
}
int main() {
print(1.2, 1, "hello");
return 0;
}
1.2 rest number of TS is 2
1 rest number of TS is 1
hello rest number of TS is 0
将函数的参数分为 一个 和 一包,递归处理第一个,一包 的数量可以为 0, 最后递归调用到 void print()
.
auto
range-base for
支持两种遍历, pass by value
和 pass by reference
.
Reference
reference 的常见用途
“reference是一种漂亮的pointer”
reference
通常不用于声明变量,而用于 参数类型(paramters type)
和 返回类型(return type)
的描述。
const
也是函数签名的一部分
// 这两个函数的签名不同
void m_func(const int&) {}
void m_func(const int&) const {}
复合&继承关系下的构造和析构
这里的结果和“面向对象(上)”里实验的结果一致。
关于 vptr 和 vtbl
范型
通过指针实现,是因为指针的内存大小都相同。 而在继承体系中,不同类的占用内存大小不一定相同。
动态绑定(多态、虚机制)的三个条件:
指针调用
指针向上转型 (
up-case
)调用的是
virtual function
关于 this
关于动态绑定
这里通过对象调用
,而非通过指针,因此这里是 static binding
, 调用了父类的函数,而非 dynamic binding
.
谈谈 const
函数重载
不必考虑函数的返回值,只考虑函数签名(非返回值的部分)。
char ch = s[5];
和 s[5] = 'a';
分别调用 const函数
和 非const函数
.
常量字符串
只调用 const函数
, 不必考虑 COW
.
关于 new, delete
new Obj()
是 new expression
, 会调用 operator new()
来进行内存分配.
重载 operator new, operator delete
重载 ::operator new, ::operator delete, ::operator new[], ::operator delete[]
这些函数由编译器调用。
重载 member operator new/delete
class Foo {
public:
void* operator new(size_t t) {
std::cout << "in overloading operator new()" << std::endl;
return ::operator new(t);
}
void operator delete(void* ptr, size_t t) { // the second parameter size_t is optional
std::cout << "in overloading operator delete(void*, size_t)" << std::endl;
::operator delete(ptr, t);
}
void operator delete(void* ptr) {
std::cout << "in overloading operator delete(void*)" << std::endl;
::operator delete(ptr);
}
};
int main() {
Foo* p = new Foo();
delete p;
}
in overloading operator new()
in overloading operator delete(void*)
重载 member operator new[]/delete[]
示例
new/delete operator
new
, new[]
完成三件事情
调用 malloc 分配内存(这一步由
::operator::new(size_t)
完成),再调用构造函数创建对象,
A::A()
返回指针
delete, delete[] 完成两件事 调用析构函数(~A()),再释放内存(operator delete(a))
可以通过 ::new
, ::delete
来绕过 member operator new/delete
, 来使用全局默认的 new & delete
重载 new(), delete() -- placement new/delete ()
Basic_String 使用 new(extra) 扩充申请量
Subscribe to my newsletter
Read articles from qilingzhao directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
