C++面向对象高级编程(下)

2-转换函数(把这种东西转换为别人的东西)

转换函数不需要返回类型,就是函数名的类型

#include<iostream>
using namespace std;
class Fraction
{
    public:
        Fraction(int num, int den = 1)
        :m_numerator(num), m_denominator(den){}

        //conversion function转换函数
        operator double() const
        {
            return double(m_numerator) / double(m_denominator);
        }

    private:
        int m_numerator;    //分子
        int m_denominator;  //分母
};

int main()
{
    Fraction f(3,5);
    //编译器会试图找一个函数让这句语句通过
    //(1)有没有定义全局的+函数,第一个参数是整数(浮点),第二个参数是fraction
    //(2)看能不能把f转为double?看看有没有这种转换函数
    double d = 4 + f;   //调用operator double() 将f转为double
    cout<<d<<endl;
    return 0;
}

3-non-explicit one argument constructor(别人的东西转换为这种东西)

two parameter ! one argument ! 可以只有一个输入

one argument -> 只要1个实参就够了!

class Fraction
{
    public:
        Fraction(int num, int den = 1):m_numerator(num), m_denominator(den){}

        //定义函数供显示转换
        Fraction operator+ (const Fraction& f);
        void print();

    private:
        int m_numerator;    //分子
        int m_denominator;  //分母
};

inline Fraction Fraction::operator+(const Fraction& f)
{
    return Fraction(m_numerator*f.m_denominator + f.m_numerator * m_denominator, m_denominator * f.m_denominator);
}

inline void Fraction::print()
{
    cout <<m_numerator<<"   "<<m_denominator<<endl;
}

int main()
{
    Fraction f(3,5);
    Fraction d2 = f+3;
    d2.print();
    return 0;
}

注意转换函数和隐式转换的构造函数不能同时存在

(一个转成double了,另一个又转成Fraction了)

想要同时存在?把构造函数改为explicit的

4-pointer-like classes(像指针的类)

想要比指针再多一些事情 -> 智能指针

在这里插入图片描述

模拟shared_ptr的写法

什么样的操作符用在指针身上呢?这里我们关注这两个操作符:*、->

总结 :智能指针里带一根一般的指针,且里面带一个、->函数*

另外需要注意的是: -> 是会连续的。例如sp->method()、sp->会返回指针px,然后px后面会再紧跟出一个->去调用它的函数method

template<class T>
class my_shared_ptr
{
    public:
        my_shared_ptr(T* ptr):px(ptr){}
        T& operator*() const
        {
            return *px;
        }
        T* operator->() const
        {
            return px;
        }
    private:
        T* px;
};

struct Foo
{
    void method()
    {
        cout<<"hello"<<endl;
    }
};


int main()
{
    //new 返回的就是指针
    my_shared_ptr<Foo> sp(new Foo());
    Foo f(*sp);
    sp->method();
    //等价于px->method
    return 0;
}

迭代器:也是一种智能指针,但是不同的是,它还需要处理 ++、-- 因为它要遍历容器

在这里插入图片描述

链表(双向)迭代器:

这里是 pointer-like classes关于迭代器 迭代器的(*、->的写法就有变化了)

在这里插入图片描述

operator*() 返回了Foo object,再去取它的地址 以调用里面的method

5-function-like classes

Pair是暗示、暗示这里要放Pair

在这里插入图片描述

标准库里有很多仿函数,他们里面都是重载了()

9-member template

模版里面还套了一个模版、外面的模版确定了之后,里面的再确定

在这里插入图片描述

在这里插入图片描述

U1 、U2 构造我 T1 和 T2 的时候,必须满足赋值动作

Derived1 是 Base1的子类

Base1* ptr = new Derived1; -> up-cast

template<typename _Tp>
class shared_ptr:public__shared_ptr<_Tp>
{
    ...
   	template<typename _Tp1>
    explicit shared_ptr(_Tp1* __p):__shared_ptr<_Tp>(__p){}
}

//智能指针
shared_ptr<Base1> sptr(new Derived1);	//模拟up-cast

10-模版特化

先举例泛化

template <class Key>
struct hash {};

特化

//已经被绑定了,所以里面的东西不在了
template<>
//在这里指定使用用charctor
struct hash<char>{
    size_t operator() (char x) const {return x;}
};

template<>
struct hash<int>{
    size_t operator() (int x) const {return x;}
};

template<>
struct hash<long>{
    size_t operator() (long x) const {return x;}
};

//调用:
// hash<long>()这部分是临时对象,后面的(1000)是调用函数
cout << hash<long>() (1000)<<endl;

11-偏特化

(无论怎么偏,要先把原来泛化的模版写出来)

template<typename T, typename Alloc>
class vector
{
    ...
}

个数上的偏

template<typename Alloc=...>
class vector<bool, Alloc>
{
    ...
}

范围上的偏(从任意类型,变成了指针类型,范围缩小了,至于它指向什么 都可以)

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

后面再决定,如果你是指针了/bool了,ok用这套偏特化的代码、不是指针就用普通的

12-模版模版参数

template**<>**里typename 和 class共通

//模版模版参数放的是容器
template<typename T, 
		 template<typename T> 
			class Container
         >
class XCls
{
    private:
    	Container<T> c;
    public:
    	...
}
//list自己还未定呢,自己还是个模版
//但是下面这个是错的	
//容器有的有第二/第三模版参数,这里过不了 很不幸运 容器需要好几个模版参数,所以过不了
XCls<string, list> mylst1;

应该这样:

template<typename T>
using Lst = List<T, allocator<T>>;

Xcls<string, Lst> mylst2;

很不幸运 容器需要好几个模版参数,所以过不了

这里使用智能指针

//模版模版参数放的是容器
template<typename T, 
		 template<typename T> 
			class SmartPtr
         >
class XCls
{
    private:
    	SmartPtr<T> sp;
    public:
    	XCls() : sp(new T) {};
}
XCls<string, shared_ptr> p1;

这不是模版模版参数

//这里
XCls<string, list> mylst1;
//我们只是传了一个list进去,它没有绑定任何东西,它仍然是一个灰色的模糊的

上面那个呢,要么不传,要么就得全部传进去,所以它不是模版模版参数

13-三个主题

数量不定的模版参数

void print()
{}

//一个和一包
template <typename T, typename... Types>
void print(const T& firstArg, const Types&... grgs)
{
    cout<<firstArg<<endl;
    print(args...);
}

//当args参数只有0个了的时候,就会调上面的print()

auto

list<string> c;
list<string>::iterator ite;
ite = find(c.begin(), c.end(), target);

变为

list<string> c;
auto ite = find(c.begin(), c.end(), target);

但是不可以下面这样

auto ite;
ite = find(c.begin(), c.end(), target);

ranged-base for

//pass by value
for(auto elem : vec)
{
	cout << elem <<endl;
}
//pass by reference
for(auto& elem : vec)
{
    elem *= 3;
}

15-Reference

一般都说:

指针指向xxx

引用代表xxx

(引用的底部实现其实也是一个指针指向别人)

在这里插入图片描述

注意系统制造出的假象:

1. sizeof(x) == sizeof®

2. &x == &r (他们的地址是一样的)

以下被视为"same signature" 不能同时存在

double imag(const double im){...}
double imag(const double& im){...}

//相同的话会二义性 Ambiguity

//?函数最后加const算不算函数签名的一部分?
//答案是是

const 被视作签名的一部分、可以同时存在

**

double imag(const double im) const{...}
double imag(const double& im) {...}

17-关于vptr和vtable

函数是代码,占内存的一块

静态绑定: call xxxx 运行完再返回来

在这里插入图片描述

它实际上运行的:

他根据虚函数的名称以及当时定义的顺序,编译器就知道它当时是把虚函数安排在了第几个

(*(p->vptr)[n])(p);
//或
(* p->vptr[n])(p);

动态绑定三个条件:

  • 通过指针调用
  • 指针是up-cast
  • 调用的是虚函数

就可以把函数编译成上面那个样子

多态、虚函数、动态绑定、说的都是同一件事

在这里插入图片描述

//这里不是指针调用的 是强行转换的,所以是静态绑定
B b;
A a = (A) b;
a.vfunc1();


//动态绑定
//(1)
A* pa = new B;
pa->vfunc1();

//(2)
pa =

call 后面不是一个固定地址了

在这里插入图片描述

18-关于this

Template method

在这里插入图片描述

这里this指的是子类的对象,所以它就符合向上转型的条件

this -> Serialize()
//等价于
(*(this -> vptr)[n])(p);

19- 关于Dynamic Binding

在这里插入图片描述

const function 这里可以被 String调用,也可以被const String调用,那这会又冲突

当成员函数const和non-const同时存在,const object 调用 const 版本、non-const object调用non-const版本

20-重载 new 和 delete

在这里插入图片描述

counter -> 让编译器知道调用5次构造、5次析构

new[] 的时候,还会另外分配4个字节做counter去记录分配了几个块

在这里插入图片描述

构造的时候向下,析构的时候向上

23-new delete 重载

在这里插入图片描述

第一参数必须是size_t

在这里插入图片描述

new内部被分成了三步

Complex* pc;
void* mem = operator new( sizeof(Complex) );	//分配内存	operator new里面用的malloc
pc = static_cast<Complex*>(mem);				//转型(malloc分配出的是void)
pc->Complex::Complex(1,2);						//构造函数

delete 内部被分成 两步

String::~String(ps);
operator delete(ps);

注意区分 operator new operator delete 和 new delete 是不一样的前面的是要带小括号使用的,后面是new表达式

24-Basic_String使用new(extra)

重载了operator new (带小括号的new)

这是class里带的class

在这里插入图片描述

当它要create它自己的时候,是要分配一个Rep,再加一个ectra(字符串放这里面)

里面的Rep就是做reference counting 引用的计数 看有多少人和我共享

什么时候要定义placement new呢?当想像这样 无声无息 不知不觉地分配一些空间的时候 可以这样借鉴

重载placement new 为的是里面有一个reference counting的设计

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值