c++oo1

c++面对对象下(0-10)笔记

类的分类

  1. 不带pointer的类
  2. 带Pointer的类: 那么 1)拷贝构造,2)拷贝赋值运算符, 3)析构函数,这3个重点函数手写,不要使用编译器默认生成的.(因为涉及到 深浅拷贝问题)

类的使用 (重载运算符)

  1. 像指针的类
  2. 像函数的类

类和类的关系

  1. 继承(Inheritance)
  2. 复合(Composition)
  3. 委托(Delegation)

1.conversion function(转换函数)

首先编译器找全局的+运算符是否重载.

然后找类是否能类型转换

在+和<<运算符作用时,Fraction类都转化为double类型了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
// #include "test.h"

class Fraction
{
public:
Fraction(int num,int den=1)
:m_numerator(num),m_denominator(den) {}
operator double() const;
private:
int m_numerator;
int m_denominator;
};

Fraction::operator double() const
{
return ((double)m_numerator/m_denominator);
}

int main()
{
Fraction a(1,2);
double ans = 1.2 + a;
std::cout << "a=" << a << " ans=" << ans;
return 0;
}

2. non-explicit-one-argument-constructer

=> implicit-one-argument-constructor

接收一个实参的隐式构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
// #include "test.h"

// implicit constructor
class Fraction
{
public:
Fraction(int num,int den=1)
:m_numerator(num),m_denominator(den) {}
Fraction operator+(const Fraction &)const;
private:
int m_numerator;
int m_denominator;

friend std::ostream& operator<<(std::ostream&,const Fraction&);
};

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

std::ostream&
operator << (std::ostream& os,const Fraction &r)
{
return os << (double)r.m_numerator/r.m_denominator << std::endl;
}


int main()
{
Fraction a(1,2);
std::cout << a+1 <<std::endl;
//等价于 std::cout<< a+Fraction(1,1) <<std::endl;
//等价与 operator<<(std::cout,a.operator+(Fraction(1,1))):

return 0;
}

歧义1: conversion function Vs. non-explicit-one-argument-constructor

学习到operator double() {}这种写法是定义类对象的类型转换.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
// #include "test.h"

// implicit constructor
class Fraction
{
public:
Fraction(int num,int den=1)
:m_numerator(num),m_denominator(den) {}
operator double() const;
Fraction operator+(const Fraction &)const;
private:
int m_numerator;
int m_denominator;

friend std::ostream& operator<<(std::ostream&,const Fraction&);
};

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

std::ostream&
operator << (std::ostream& os,const Fraction &r)
{
return os << (double)r.m_numerator/r.m_denominator << std::endl;
}

Fraction::operator double() const
{
return (double)m_numerator / m_denominator;
}


int main()
{
Fraction a(1,2);
std::cout << a+1 <<std::endl;
// 1.std::cout<< a+Fraction(1,1) <<std::endl;
// 2.std::cout << operator double(a) + 1 << std::endl;

return 0;
}

可以看到这里有二义性.a可以执行类型转换,且1可以进行隐式构造.

解决:构造函数explicit,明确化,不允许隐式类型转换.

3.pointer-like classes

像指针的类

主要是需要重载类的2个运算符

  1. *:返回的T&,也就是指向对象的本身(引用)
  2. ->:返回的是指针,将类自己的指针成员暴露出来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>

template<typename T>
class shared_ptr
{
public:
T& operator*()const;
T* operator->()const;
private:
T* px;
long *pn;
};

template<typename T>
T&
shared_ptr<T>::operator*()const
{
return *px;
}

template<typename T>
T*
shared_ptr<T>::operator->()const
{
return px;
}


int main()
{

return 0;
}

4.function-like-classes

像函数的类

主要是重载()运算符,operator()(),然后下面是随便写的一段测试小代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <iostream>

namespace Luchao
{
template<typename T1,typename 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) {}

friend std::ostream& operator<<(std::ostream&,const pair<int,double>&);
};

template<typename T>
struct identity
{
const T& operator()(const T&) const;
int operator()()const;
};

template<typename T>
const T&
identity<T>::operator()(const T& x)const
{
return x;
}

template<typename T>
int
identity<T>::operator()()const
{
std::cout << "identity()" << std::endl;
return 1;
}

template<typename Pair>
struct select1st
{
const typename Pair::first_type& operator()(const Pair&)const;
};

template<typename Pair>
const typename Pair::first_type&
select1st<Pair>::operator()(const Pair&r)const
{
return r.first;
}

template<typename Pair>
struct select2nd
{
const typename Pair::second_type& operator()(const Pair&)const;
};

template<typename Pair>
const typename Pair::second_type&
select2nd<Pair>::operator()(const Pair& r)const
{
return r.second;
}

std::ostream& operator << (std::ostream& os,const pair<int,double>& r)
{
return os << "(" <<r.first << "," << r.second << ")" << std::endl;
}
}

std::ostream& operator<<(std::ostream& os,const std::pair<int,double>& r)
{
return os << "(" << r.first << "," << r.second << ")" << std::endl;
}

int main()
{
std::pair<int,double> a(1,2.3);
Luchao::pair<int,double> l(9,9.8);
std::cout << a;
std::cout << l;

std::cout << "---" << std::endl;
Luchao::identity<Luchao::pair<int,double>> lcidentity;
Luchao::identity<std::pair<int,double>> stdidentity;
std::cout << lcidentity(l);
std::cout << stdidentity(a);

int first = Luchao::select1st<std::pair<int,double>>()(a);
double second = Luchao::select2nd<Luchao::pair<int,double>>()(l);
std::cout << first << std::endl;
std::cout << second << std::endl;
return 0;
}

5.namespace

模板的分类

6.class template(类模板)

7.function template(函数模板)

函数接收的参数支持多种类型.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>

template<typename T>
inline
const T&
min(const T& a,const T& b)
{
// return b < a ? b : a;
return a < b ? a : b;
}

class stone
{
public:
stone() = default;
stone(int w,int h,int we = 0)
:_w(w),_h(h),_weight(we) {}
bool operator < (const stone&)const;
private:
int _w,_h,_weight;

friend std::ostream& operator<< (std::ostream&,const stone&);
};

bool
stone::operator<(const stone& r)const
{
return _weight < r._weight;
}

std::ostream& operator << (std::ostream& os,const stone &r)
{
return os << "(" << r._w << " " << r._h << " " << r._weight << ")" << std::endl;
}

int main()
{
stone r1(2,3,1),r2(3,3,4),r3;
r3 = min(r1,r2);
std::cout << r3;
return 0;
}

模板函数调用,既可以手动指出参数类型,也可以不指出

下面是function template(函数模板) vs. function-like template class(像函数的模板类),实现相同的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>

namespace Luchao
{
template<typename T1,typename 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<typename T1,typename T2>
void func(const pair<T1,T2> &r)
{
std::cout << "(" << r.first << " " << r.second << ")" << std::endl;
}

/*模板类实现打印:function like class*/
template<typename T1,typename T2>
class Func
{
public:
void operator()(const pair<T1,T2>&)const;
};
template<typename T1,typename T2>
void
Func<T1,T2>::operator()(const pair<T1,T2>& r)const
{
std::cout << "(" << r.first << " " << r.second << ")" << std::endl;
}
}


int main()
{
Luchao::pair<int,int> a(1,2);
Luchao::pair<int,double> b(1,9.9);
Luchao::pair<int,double> c(b);

Luchao::func<int,int>(a);
Luchao::func(a);
Luchao::func(c);
Luchao::Func<int,double>()(c);

return 0;
}

8.member template(成员模板)

在一个模板类中,使用成员模板函数作为其构造函数,可以接收其它类型的变量(例如类的成员变量是基类,但传入的是父类变量来构造)作为构造参数.

如shared_ptr的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>

namespace llc
{
class Base1
{};
class Base2
{};
class Derived1:public Base1
{};
class Derived2:public Base2
{};

template<typename T1,typename 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) {}

/*成员模板 member-template,参数U1和U2是独立的,注意独立的意思*/
template<typename U1,typename U2>
pair(const llc::pair<U1,U2>& p)
: first(p.first),second(p.second) {}
};
}

template<typename T1,typename T2>
void func(llc::pair<T1,T2>& r)
{
std::cout << "(" << r.first << " " << r.second << ")" << std::endl;
}

template<typename T1,typename T2>
class Func
{
public:
void operator()(const llc::pair<T1,T2>& r) const
{
std::cout << "(" << r.first << " " << r.second << ")" << std::endl;
}
};

int main()
{
{
llc::pair<int,int> a(1,2);
llc::pair<int,double> b(1,9.9);
llc::pair<int,int> c(b);

func<int,int>(a);
func(b);
Func<int,int>()(c);
Func<int,double>()(b);
}

//关于构造的问题
llc::pair<llc::Derived1,llc::Derived2> b;
llc::pair<llc::Base1,llc::Base2> a(b);

return 0;
}

9. specialization,模板特化

泛化(也就是普通的模板):

对于特殊的类型想要特殊处理,就将此类型的类单独拿出来写一遍,叫做特化

注意,有泛化(也就是有模板类)才有特化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>

namespace Luchao
{
template<typename T>
struct hash
{
hash()=default;
};

template<>
struct hash<long>
{
long operator()(long x)const{return x;}
};
template<>
struct hash<int>
{
int operator()(int x)const{return x*2;}
};

template<>
struct hash<char>
{
char operator()(char c)const{return c;}
};
}

int main()
{
std::cout << Luchao::hash<int>()(100);
return 0;
}

10. 模板偏特化 (partial specialization)

1. 参数个数偏特化(从左到右,根据需要特化)

例子不是很恰当

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>

namespace Luchao
{
template<typename T1,typename T2>
class Tmp
{
public:
Tmp()=default;
Tmp(const T1& a,const T2& b):a(a),b(b){};
void printf()const {std::cout << "base" << std::endl;}
private:
T1 a;
T2 b;
};
template<typename T2>
class Tmp<bool,T2>
{
public:
Tmp()=default;
Tmp(const T2& b):flag(true),b(b){}
void printf()const{std::cout<< "partial specialization" << std::endl;}
private:
bool flag;
T2 b;
};
}

int main()
{
Luchao::Tmp<int,std::string> t1;
Luchao::Tmp<bool,std::string> t3;
t1.printf();
t3.printf();
return 0;
}

2. 范围上的偏特化

如:本来接受任意类型T,可以通过特化将类型缩小到指针,(指针本身是一种类型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>

namespace Luchao
{
//1.T默认的泛化接收所有类型,假设T=int*,那么可以特化成接收类型是指针的版本
template<typename T>
class vector
{
public:
vector():data(){}
vector(const T& r):data(r){}
const T& get()const {return data;}
int printf()const{return data.length();};
private:
T data;
};
//此T类型并不是上面的T,如果上面的T推导得到char*,则特化指针类型时,此T表示char
template<typename T>
//因为是外部传入的指针,所以资源的所有权不由我们控制,所以不写析构
class vector<T*>
{
public:
vector():data(nullptr){}
vector(T* p):data(p){}
vector(const T* p):data(p){}
const T& get()const{ return *data;}
private:
T *data;
};
}

int main()
{
//1.泛化
Luchao::vector<std::string> t(std::string("llc"));
std::cout << t.get() << std::endl;

//2.特化例子
std::string *str = new std::string("abc");
Luchao::vector<std::string*> t1(str);
std::cout << t1.get() << std::endl;
delete str;

return 0;
}

看了前11集没看了,然后去看effective 和insight class model,现在接着看.