//定义
class Fraction{
public:
Fraction(int num, int den = 1) : m_numerator(num), m_denominator(den){}
//here!here!
operator double() const {
return (double)(m_numerator / m_denominator);
}
private:
int m_numerator;
int m_denominator;
}
//使用
Fraction f(3,5);
double d2 = 4 + f;//转换函数将f转换成double类型,然后4隐式转换成double,从而相加
//定义
class Fraction{
public:
//here!here!
Fraction(int num, int den = 1) : m_numerator(num), m_denominator(den){}
Fraction operator+(const Fraction& F) {
return Fraction(……);
}
private:
int m_numerator;
int m_denominator;
}
//使用
Fraction f(3,5);
double d2 = f + 4;//调用non-explict ctor 将4转换成Fraction类,从而可以调用operator+
//cf和neoac均存在的定义
class Fraction{
public:
//here!here!
Fraction(int num, int den = 1) : m_numerator(num), m_denominator(den){}
//here!here!
operator double() const {
return (double)(m_numerator / m_denominator);
}
Fraction operator+(const Fraction& F) {
return Fraction(……);
}
private:
int m_numerator;
int m_denominator;
}
//使用
Fraction f(3,5);
Fraction d2 = f + 4;
//此时会报错:ambiguous
//存在两条可行的路线:f->double->double+double->Fraction或者4->Fraction->Fraction+Fraction->Fraction
//cf和neoac均存在的定义
class Fraction{
public:
//here!here!
explict Fraction(int num, int den = 1) : m_numerator(num), m_denominator(den){}
operator double() const {
return (double)(m_numerator / m_denominator);
}
Fraction operator+(const Fraction& F) {
return Fraction(……);
}
private:
int m_numerator;
int m_denominator;
}
//使用
Fraction f(3,5);
Fraction d2 = f + 4;
//该例是上一个例子仅在ctor前加上explict关键字
//此时仍然报错,是因为没有一条可行的路线,因为不能将4转换成Fraction类型,所以无法走operator+以及double+完后转成Fraction的这两条路线
//智能指针定义
template
class shared_ptr{
public:
//here!here!
T& operator*() const{
return *px;
}
//here!here!
T* operator->() const{
return px;
}
shared_ptr(T* p) : px(p) {}
private:
T* px;
long* pn;
};
//使用
struct Foo{
void method(void);
};
shared_ptr sp(new Foo);
Foo f(*sp);
sp->method();//调用了智能指针重载的->,返回了其中存放的指针px,但是->的特性是持续作用于对象上,所以对px继续做->操作
template
struct _list_iterator {
……
typedef _list_node* link_type;
link_type node;
reference operator*() const {return (*node).data;}
pointer operator->() const {return &(operator*());}
……
}
template
struct _list_node {
void* prev;
void* next;
T data;
}
list::iterator ite;
……
*ite;//意思是从Foo对象的链表里获得一个Foo object
ite->method();
//意思是调用Foo::method()
//相当于 (*ite).method() 此时是调用Foo对象的method方法
//相当于 (&(*ite))->method() 此时是调用Foo对象指针的method方法
template
struct identity {
const T& operator()(const T& x) const {return x;}
};
template
struct select1st {
const typename Pair::first_type&
operator() (const Pair& x) const
{return x.first;}
};
template
struct select2nd {
const typename Pair::second_type&
operator ()(const Pair& x) const
{return x.second;}
};
//std定义一个pair类,可以放入两种类型
template
struct pair {
T1 first;
T2 second;
……
}
实则仿函数的完整写法如下,会继承一个类,下图继承unary_function
下图继承binary_function
下图是unary_funtion类和binary_function类,前者用于单操作数的仿函数继承,后者用于双操作数的仿函数继承
(I)课程中的复数类
函数模板无需指定类型名称,编译器会针对function template做实参推导,注意通用的处理逻辑可能需要自定义类型自行进行操作符重载一类的定义
//实例一
//定义
template
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
pair(const pair& p) : first(p.first), second(p.second){}
};
//使用
class 鱼类 {};
class 鲫鱼 : public 鱼类 {};
class 鸟类 {};
class 麻雀 : public 鸟类 {};
pair<鱼类,鸟类> p;
pair<鲫鱼,麻雀> p2(p);
//等同于下面
pair<鱼类,鸟类> p2(pair<鲫鱼,麻雀>());
//实例二
//定义
template
class shared_ptr : public _shared_ptr<_TP>{
template
explicit shared_ptr(_Tp1* _p):_shared_ptr<_Tp>(_p){}
};
//使用
Base* ptr = new Derived1;
//shared_ptr想实现 派生类和基类 间的向上转型,如下
shared_ptr sptr(new Derived1);
template
struct hash {};
template<>
struct hash{
size_t operator()(char x) const {return x;}
};
template<>
struct hash{
size_t operator()(int x) const {return x;}
};
template<>
struct hash{
size_t operator()(long x) const {return x;}
};
//使用
cout << hash()(1000);//hash() 用于寻找特化的模板
//(1000)的小括号用来调用操作符
//实例一,个数上的“偏”
template
class vector{
};
template
class vector{
};
//实例二,范围上的“偏”
template
class C{
};
template
class C{
};
//使用
C obj1; //使用实例二中的第一套泛化模板
C obj2; //使用实例二中的第二套偏特化模板
见实例,语法较简单
//实例一
//定义
template
class Container
class XCls{
private:
Container c;
public:
};
//使用
XCls mylst1; //报错,因为list除了元素类型这一参数外,还有分配器的参数,所以需要提前指定后才能使用。
XCls mylst2; //正确
template
using Lst = list>;
//实例二--------------------------------------
//定义
template
class SmartPtr
class XCls{
private:
SmartPtr sp;
public:
XCls() : sp(new T){}
};
//使用
XCls p1; //正确,大部分智能指针只有一个模板参数,所以此处的报错与此无关,与各自指针的特性有关。
XCls p2; //正确
XCls p3; //错误
XCls p4; //错误
//实例三------------------------------------
//定义
template>
class stack{
protected:
Sequence c; //底层对象
};
//使用
stack s1;
stack> s2;
//print的空参数重载定义
void print(){
}
//print的模板函数定义
template
void print(const T& firstArg, const Type&… args){
cout<
//情况一
list c;
list::iterator ite;
ite = find(c.begin(), c.end(), target);
//情况二,等价情况一
auto ite = find(c.begin(), c.end(), target);
//情况三,错误,未赋值,编译器无法自动推导变量类型
auto ite;
ite = find(c.begin(), c.end(), target);
//decl 是一个自定义的变量名 coll必须是一个容器
for (decl : coll) {
statement
}
vector vec;
for (auto elem : vec) {
cout << elem << endl; //因为是pass by value 修改elem不会影响vec中的元素
}
for (auto& elem : vec) {
elem *= 3; //pass by reference
}
int x = 0; //x是一个变量,int类型。
int* p = &x; //p是一个变量,pointer to integer,p指向x。
int& r = x; //r是一个变量,reference to integer,r代表x。
int x2 = 5;
r = x2; //并不代表r代表x2了,只是r的值改成了x2的值,此时r和x的值都是5
int& r2 = r; //r2代表r,r代表x,即r2代表x
double imag(const double& im){}
double imag(const double im){} //Ambiguity
分析:
分析:
只要有虚函数,不管有多少个,只会在对象中除虚函数以外所有的变量和函数之和的基础上增加4个字节(一根指针)
只要父类中定义了虚函数(对象内存有一根指针),子类中也会有虚函数(对象内存也有一根指针)。函数的继承指的是继承函数的调用权。
静态绑定:call XXX。动态绑定:三大条件——通过指针,该指针向上转型,指针调用的是虚函数,此时编译器走的路线就是虚函数到虚表,如下:
(*(p->vptr)[n])(p);
(* p->vptr[n])(p);
动态绑定-虚机制-多态。虽然都是用的父类指针,但是却指向的不同的类型。
B b;
A a = (A)b;
a.vfunc1(); //此时a是对象,就算是用b转型后赋值,也是不满足动态绑定的条件的,此处依然是静态绑定
A* pa = new B;
pa->vfunc1(); //dynamic binding
pa =&b;
pa->vfunc1(); //dunamic binding
在此处特谈const用在类成员函数的用法
const可用在成员函数中,且一般不用于全局函数。
const放在函数参数的小括号后,函数体的大括号前
//实例一
const String str("hello world");
str.print();
//实例二
charT
operator[](size_type pos) const {/*不必考虑COW*/};
reference
operator[](size_type pos) {/*必须考虑COW*/}
//COW:Copy On Write
CDocument::OnFileOpen(&myDoc);
此时有指针条件,也满足向上转型。同时在执行到serialize函数时,补充为:
this->serialize();
满足调用虚函数的条件,此时实现动态绑定机制。
new 和 delete是不能被重载的。
但是在Part I中知道,new和delete的实现基于operator new 和 operator delete。
这两个函数是可以被我们重载的。
重载的接口写法示例:(实例一)
类中的operatpr new 和 delete 重载:(实例二)
类中的operatpr new[] 和 delete[] 重载:(实例三)
一个完整的重载示例:(实例四)
重载后窥见new和delete实际做的动作:(实例五)
placement实质上还是对operator new 和 delete 的重载。
上面重载类型属于对global operator new 和 delete的定义重写,参数类型和数量都与global一致。
placement在保持与global的参数相同的基础上,可额外加上其他的参数类型。
//placement重载后创建对象的例子
FOO* pf = new(300,'c')Foo;
给出在类中写出的placemnet 重载的实际例子
2个构造函数(无参和有参抛异常) 4个operator重载new(1个一般重载、1个标准库placement重载、2个自定义placement重载)
根据实例二的operator new重载写出对应的operator delete
同时使用多个重载new和两个构造函数创建对象
string中的reference counting(当前字符串有多少对象共享的计数器)的设计
string类中的rep类的create函数——使用placement operator new创建rep对象
Rep* p = new(extra) Rep;