对于1个类要么像指针要么像函数
主题1:转换函数
转换函数
/** 1. 转换函数没有返回类型* 2. 转换函数一般需要加上const*/
class Fraction
{
public:Fraction(int num,int den=1):m(num),n(den){cout<<"Fraction(int num,int den=1): m/n = "<< m/n<<endl;}operator double()const{cout<<"调用转换函数double():"<<(double)( m/n )<<endl;return (double)( m/n );}
private:int m;int n;
};
int main(int argc, char** argv)
{Fraction f(8,2);double d = 5 + f;/** 首先 4* */
// Fraction d = f + 4;cout<<d<<endl;/** 输出结果:* Fraction(int num,int den=1):m/n = 4* 调用转换函数double()* 8* 分析:f(8,2): 首先调用构造函数* 然后;5 + f 中的f调用转换函数转换为double*/
}
non-explict-one-argument ctor
class Fraction
{
public:Fraction(int num,int den=1):m(num),n(den){cout<<"Fraction(int num,int den=1): m/n = "<< m/n<<endl;}Fraction operator+(const Fraction &f){cout<<"调用operator+()函数"<<endl;return Fraction(m+f.m,n+f.n);}
private:int m;int n;
};
int main(int argc, char** argv)
{Fraction f(8,2);Fraction d1 = f+5;// === f.operator+(5);/** 首先f+5中的5调用构造函数Fraction(int num,int den=1)* 然后调用operator+()函数*/
}
注意:提供默认值的构造函数可以将一种类中的为提供默认值的属性类型转换为该类类型---即将一种类型转化为本类类型 operaor double() --- 则是将本类型转化为double类型,两者转换方向刚好相反;但是我们一般所说的转换函数是后一种类型;
ambiguous error
class Fraction
{
public:Fraction(int num,int den=1):m(num),n(den){cout<<"Fraction(int num,int den=1): m/n = "<< m/n<<endl;}operator double()const{cout<<"调用转换函数double():"<<(double)( m/n )<<endl;return (double)( m/n );}Fraction operator+(const Fraction &f){cout<<"调用operator+()函数"<<endl;return Fraction(m+f.m,n+f.n);}
private:int m;int n;
};
Fraction operator+(int a,const Fraction &b)
{
//解决5+f的问题
}
int main(int argc, char** argv)
{Fraction f(8,2);Fraction d1 = f+5;// Use of overloaded operator '+' is ambiguous (with operand types 'Fraction' and 'int')Fraction d1 = 5+f;
}
explict的使用:一般用在构造函数前面,表示此构造函数只能用于构造不能用于其他目的
explicit Fraction(int num,int den=1):m(num),n(den)
Fraction d1 = f+5;// error
但是仍然会出现:error: conversion from ‘double’ to non-scalar type ‘Fraction’ requested
解释:
f+5中首先由于在构造函数前面加上了explict所以不会ambiguous,f首先转换为double记为a,然后执行a+5后产生一个double记为c,但是c不能转化为Fraction,因为explict
坑
:
Fraction operator+(int a,const Fraction &b)
{
//解决5+f的问题
}
是否可以成员函数实现,是否是下面的
class Fraction
{friend Fraction operator+(int a,const Fraction &f){;} //注意这不是Fraction的成员函数,这个是全局函数。只不过在Fraction中声明为友元函数之后直接实现了。
}
//这里的5+f的实现利用friend成员函数没有this指针的特点
关于友元函数
- 友元函数没有this指针
- 因为友元函数是类外的函数,所以它的声明可以放在类的私有段或公有段且没有区别。
- 友元函数是不能被继承的,就像父亲的朋友未必是儿子的朋友
友元函数的分类:
根据这个函数的来源不同,可以分为三种方法:
普通函数友元函数:
目的:使普通函数能够访问类的友元
语法:
声明: friend + 普通函数声明
实现位置:可以在类外或类中
实现代码:与普通函数相同
调用:类似普通函数,直接调用
class INTEGER{friend void Print(const INTEGER& obj);//声明友元函数};void Print(const INTEGER& obj){//函数体}void main(){INTEGER obj;Print(obj);//直接调用}
类Y的所有成员函数都为类X友元函数—友元类
目的:使用单个声明使Y类的所有函数成为类X的友元,它提供一种类之间合作的一种方式,使类Y的对象可以具有类X和类Y的功能。
语法:
声明位置:公有私有均可,常写为私有(把类看成一个变量)
声明: friend + 类名(不是对象哦)
class girl;class boy{public:void disp(girl &);};void boy::disp(girl &x) //函数disp()为类boy的成员函数,也是类girl的友元函数{cout<<"girl's name is:"<<x.name<<",age:"<<x.age<<endl;//借助友元,在boy的成员函数disp中,借助girl的对象,直接访问girl的私有变量}class girl{private:char *name;int age;friend boy; //声明类boy是类girl的友元};
类Y的一个成员函数为类X的友元函数
目的:使类Y的一个成员函数成为类X的友元,具体而言:在类Y的这个成员函数中,借助参数X,可以直接以X的私有变量
语法:
声明位置:声明在公有中 (本身为函数)
声明:friend + 成员函数的声明
调用:先定义Y的对象y—使用y调用自己的成员函数—自己的成员函数中使用了友元机制
代码:
实现代码和2.4.2.3中的实现及其相似只是设置友元的时候变为friend void boy::disp(girl &);
主题2:pointer-like classes 智能指针
pointer-like classes 智能指针
template<class T>
class shared_ptr
{
public:T& operator*()const{return *px;}T* operator->()const{return px;}shared_ptr(T* p):px(p){};
private:T* px;long *pn;
};
struct FOO
{void method();
};
int main(int argc, char** argv)
{shared_ptr<FOO> sp(new FOO);FOO f(*sp);sp->method(); // == px->method(0) ->会作用之后会继续出现->return 0;
}
pointer-like classes 迭代器
template <class T, class Ref, class Ptr>
struct __list_iterator { //这是一个链表typedef __list_iterator<T, Ref, Ptr> self;typedef Ptr pointer;typedef Ref pointer;typedef __list_node<T>* link_type;link_type node;bool operator==(const self& x) const { return node == x.node; }bool operator==(const self& x) const { return node != x.node; }reference operator*() const { return (*node).data; }pointer operator-> const { return &(operator*())}self& operator++() { node = (link_type)((*node).next); return *this }self& operator++(int) { self tmp = *this; ++*this; return tmp; }self& operator--() { node = (link_type)((*node).prep); return *this }self& operator--(int) { self tmp = *this; --*this; return tmp; }
};
主题3: function-like classes 仿函数
template<class T>
struct identity
{const T& operator()(const T& x)const{return x;}
};
主题4:namespace
#include <iostream>
#include<list>namespace jj01
{
//开始设计template<typename T>using Lst=list<T,allocator<T>>;void test()
}
int main()
{jj01::test()
}
主题6: 模板
class template,类模板
Function template 函数模板
member template 成员模板
template <class T1,class T2>
struct pair {typedef T1 first_type;typedef T2 second_type;T1 first;T2 second;pair() :first(T1()),second(T2()) { }pair(const T1& a,const T2& b) :first(a), second(b) { }template <class U1,class U2> //这里,模板套模板,成员模板pair(const pair<U1,U2>& p): first(p.first),second(p.second) { }
};class Base1{};
class Derived1:public Base1{};pair<Derived1,Derived2> p;
pair<Base1,Base2> p2(p);
等价于pair<Base1,Base2> pw(pair<Derived1,Derived2>()); //用子类初始化父类
specialization 模板特化
template <class Key>
struct hash { };
--------------------上面的是泛化-------
template<> //Key被锁定了
struct hash<char> {size_t operator() (char x) const { return x; }
};template<> //Key被锁定了
strcut hash<int> {size_t operator() (int x) const {return x; }template<> //Key被锁定了
struct hash<long> {size_t operator() (long x) const { return x; }
};
parti specialization 模板偏特化
个数的偏
因为上面的模板有两个参数,但是目前我只需一个值绑定一个
范围的偏
template template parameter 模板模板参数
XCIS<string,list> mylist1; 第一个确定为string,但是第二个不确定传入模板;但是是错误的;虽然 Container变为 list但是一些容器的模板有一个以上的参数,我们一般只是定义了一个参数,上面不通过是由于语法问题参数不足导致
打岔:由于unique和weak的一些特性导致错误。
上面不是模板模板参数,由于list已经指定模板了
variadic templates 数量不定的模板参数
void print()
{cout<<"------"<<endl;}template<typename T,typename ... Types>
void print(const T& firstArg,const Types&...args)
{// 参数:一个 + 一包cout<<firstArg<<endl;cout<<sizeof...(args)<<ends;print(args...);
}
int main()
{print(7.5,"hello",42);/*
7.5
2 hello
1 42
0 ------这个模板参数可变的函数:参数可以分为一个+一包,这个函数是递归调用首先是:print(first=7.5,args=("hello",42)) 然后输出firstArg,然后size...(args)==2然后是:print(first="hello",args=(42)),打印出“hello”然后size...(args)==1最后是:print(first=42,args=),打印42,然后size...(args)===1调用无参数的print()*/return 0;
}
C++标准库
for(int i:{1,2,3,4})cout<<i;
//{1,2,3}是个容器
主题7:reference 引用
- object和其reference的大小相同,地址也相同(全都是假象)
- reference通常不用于声明变量,一般用于函数的参数类型和函数返回类型
主题8:对象模型
继承关系下的构造和析构
- 构造应该由内而外
- 析构应该由外二内
组合关系下的构造和析构
- 构造应该由内而外
- 析构应该由外二内
继承+组合 关系下的构造和析构
对象模型:vptr(虚指针)和vtbl(虚表)
- 只要一个类含有虚函数,那么该类一定含有虚指针。多一个虚函数就多一个虚指针
- 父类有虚函数子类一定有虚函数
函数: - 静态绑定
- 动态绑定
动态绑定的条件
- 虚函数
- 向上转型
this
主题9:const
- const只能放在成员函数后面
主题10:new delete
重载 operator new,operator new[],operator delete,operator delete[]
https://zhuanlan.zhihu.com/p/526244459
placement new
https://blog.csdn.net/qq_41453285/article/details/103547699
关于这里没有看明白(最后几节)