侯捷cpp-oop(下) 笔记

qilingzhaoqilingzhao
4 min read

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 ctor4 转化为 Fraction 类型, 再传递进入 operator+ .

explict

explict 会告诉编译器不要进行隐式转换, 可以用来修饰ctorconversion 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_functionbinary_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 valuepass 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

范型通过指针实现,是因为指针的内存大小都相同。 而在继承体系中,不同类的占用内存大小不一定相同。

动态绑定(多态、虚机制)的三个条件:

  1. 指针调用

  2. 指针向上转型 (up-case)

  3. 调用的是 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[] 完成三件事情

  1. 调用 malloc 分配内存(这一步由::operator::new(size_t)完成),

  2. 再调用构造函数创建对象, A::A()

  3. 返回指针

delete, delete[] 完成两件事 调用析构函数(~A()),再释放内存(operator delete(a))

可以通过 ::new , ::delete 来绕过 member operator new/delete, 来使用全局默认的 new & delete

重载 new(), delete() -- placement new/delete ()

Basic_String 使用 new(extra) 扩充申请量

0
Subscribe to my newsletter

Read articles from qilingzhao directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

qilingzhao
qilingzhao