c++

14.2 多继承
一个派生类同时继承多个基类的行为。

多继承容易让代码逻辑复杂、思路混乱,一直备受争议,中小型项目中较少使用,后来的 Java、C#、PHP 等干脆取消了多继承。

多重继承派生类声明的一般形式:

class 派生类名:继承方式1 基类1,继承方式2 基类2
{
派生类主体;
};
1
2
3
4
多重继承派生类的构造函数:

派生类名(总参数列表):基类名1(基类参数列表1),基类名2(基类参数列表2),
子对象名1,…(参数列表)
{
构造函数体;
}`
1
2
3
4
5
二义性问题:多个基类中有同名成员,出现访问不唯一的问题。

1.类名::同名成员名;
2.派生类定义同名成员,访问的就是派生类同名成员。
14.3 虚基类
c++引入虚基类使得派生类再继承间接共同基类时只保留一份同名成员。

虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual Base Class)。
派生类的 同名成员 比虚基类的 优先级更高
虚基类的声明:class 派生类名:virtual 继承方式 基类名
class A//虚基类
{
protected:
int a;
};
class B: virtual public A
{
protected:
int b;
};
class C:virtual public A
{
protected:
int c;
};
class D:public B,public C
{
protected:
int d;
void show()
{
b = 123;
c = 23;
a = 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
如果 B 或 C 其中的一个类定义了a,也不会有二义性,派生类的a 比虚基类的a 优先级更高。
如果 B 和 C 中都定义了 a,那么D直接访问a 将产生二义性问题。
应用:c++中的iostream , istream , ostream,base_io
15 多态和虚函数
15.1 向上转型
数据类型的转换,编译器会将小数部分直接丢掉(不是四舍五入)

int a = 66.9;
printf("%d\n", a);//66
float b = 66;
printf("%f\n", b);//66.000000
1
2
3
4
只能将将派生类赋值给基类(C++中称为向上转型): 派生类对象赋值给基类对象、将派生类指针赋值给基类指针、将派生类引用赋值给基类引用
派生类对象赋值给基类对象,舍弃派生类新增的成员;派生类指针赋值给基类指针,没有拷贝对象的成员,也没有修改对象本身的数据,仅仅是改变了指针的指向;派生类引用赋值给基类引用,和指针的一样。、
上转型后通过基类的对象、指针、引用只能访问从基类继承过去的成员(包括成员变量和成员函数),不能访问派生类新增的成员

15.2 多态
不同的对象可以使用同一个函数名调用不同内容的函数。

静态多态性-在程序编译时系统就决定调用哪个函数,比如函数重载和静态多态性
动态多态性-在程序运行过程中动态确定调用那个函数,通过虚函数实现的。
15.3 虚函数
实现程序多态性的一个重要手段,使用基类对象指针访问派生类对象的同名函数。

将基类中的函数声明为虚函数,派生类中的同名函数自动为虚函数。
声明形式:virtual 函数类型 函数名 (参数列表);
构造函数不能声明为虚函数,析构函数可以声明为虚函数。
class A
{
public:
virtual void show()
{
cout << “A show” << endl;
}
};
class B: public A
{
public:
void show()
{
cout << “B show” << endl;
}
};
int main()
{

B b;
b.show();//B show
A *pA = &b;
pA->show();//B show 如果show方法前没用virtual声明为虚函数,这里会输出A show

system("pause");
return 0;

}
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
15.4 纯虚函数
在基类中不执行具体的操作,只为派生类提供统一结构的虚函数,将其声明为虚函数。

class A
{
public:
virtual void show() = 0;
};
class B: public A
{
public:
void show()
{
cout << “B show” << endl;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
抽象类:包含纯虚函数的类称为抽象类。由于纯虚函数不能被调用,所以不能利用抽象类创建对象,又称抽象基类。

16 运算符重载
所谓重载,就是赋予新的含义。函数重载(Function Overloading)可以让一个函数名有多种功能,在不同情况下进行不同的操作。运算符重载(Operator Overloading)也是一个道理,同一个运算符可以有不同的功能。

运算符重载是通过函数实现的,它本质上是函数重载。
允许重载的运算符

运算符名称 运算符
双目算术运算符 +、-、、、、%
关系运算符 ==、!=、<、>、<=、>=
逻辑运算符 ||、&&、!
单目运算符 +、-、
(指针)、&(取地址)
自增自减运算符 ++、–
位运算符 |、&、-、……、<<、>>
赋值运算符 =、+=、-=、=、/=、%=、&=、!=、^=、<<= 、>>=
空间分配和释放 new、delete、new[]、delete[]
其他运算符 ()(函数调用) 、->(成员访问)、->
(成员指针访问)、,(逗号)、
不允许重载的运算符
运算符名称 运算符
成员访问运算符 .
成员指针访问运算符 . *
域运算符 ::
长度运算符 sizeof()
条件运算符 ?:
16.1 定义
重载运算符遵循的规则:

不可以自己定义新的运算符,只能对已有的C++运算符重载。
不能改变运算符运算对象的个数。
不能改变运算符的优先级和结合性
应与标准类型运算功能相似,避免影响可读性。
一般格式:
函数类型 operator运算符(参数列表)
{
函数体
}
//举个栗子:定义一个向量类,通过运算符重载,可以用+进行运算。
class Vector3
{
public:
Vector3();
Vector3(double x,double y,double z);
public:
Vector3 operator+(const Vector3 &A)const;
void display()const;
private:
double m_x;
double m_y;
double m_z;
};
Vector3::Vector3() :m_x(0.0), m_y(0.0), m_z(0.0) {}
Vector3::Vector3(double x, double y,double z) : m_x(x), m_y(y), m_z(z) {}
//运算符重载
Vector3 Vector3::operator+(const Vector3 &A) const
{
Vector3 B;
B.m_x = this->m_x + A.m_x;
B.m_y = this->m_y + A.m_y;
B.m_z = this->m_z + A.m_z;
return B;
}
void Vector3::display()const
{
cout<<"(" << m_x << “,” << m_y << “,” << m_z << “)” << endl;
}
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
16.2 形式
运算符重载的形式有两种:重载函数作为类的成员,重载函数作为类的友元函数
根据运算符操作数的不同:双目运算符作为类成员函数,单目运算符作为类的成员函数,双目运算符作为类的友员函数,单目运算符作为类的友元函数。

双目运算符作为友元函数时需要制定两个参数。
运算符重载函数作为类成员函数可以显式调用。
class Vector3
{
public:
Vector3();
Vector3(double x,double y,double z);
public:
Vector3 operator+(const Vector3 &A)const;
Vector3 operator++();
friend Vector3 operator-(const Vector3 &v1, const Vector3 &v2);
friend Vector3 operator–(Vector3 &v);
void display()const;
private:
double m_x;
double m_y;
double m_z;
};
Vector3::Vector3() :m_x(0.0), m_y(0.0), m_z(0.0) {}
Vector3::Vector3(double x, double y,double z) : m_x(x), m_y(y), m_z(z) {}
//运算符重载
Vector3 Vector3::operator+(const Vector3 &A) const
{
Vector3 B;
B.m_x = this->m_x + A.m_x;
B.m_y = this->m_y + A.m_y;
B.m_z = this->m_z + A.m_z;
return B;
}
Vector3 Vector3::operator++()
{
this->m_x ++;
this->m_y ++;
this->m_z ++;
return *this;
}
void Vector3::display()const
{
cout<<"(" << m_x << “,” << m_y << “,” << m_z << “)” << endl;
}
Vector3 operator-(const Vector3 &v1,const Vector3 &v2)
{
Vector3 B(v1.m_x - v2.m_x, v1.m_y - v2.m_y, v1.m_z - v2.m_z);
return B;
}
Vector3 operator–( Vector3 &v)
{
v.m_x–;
v.m_y–;
v.m_z --;
return v;
}
int main()
{
Vector3 v1(1, 2, 3);
Vector3 v2(2, 3, 2);

++v1;//v1.operator++(); 作为类成员函数可以显式调用
v1.display();
--v2;
v2.display();
Vector3 v3 = v1 + v2;// v1.operator+(v2);作为类成员函数可以显式调用
v3.display();
Vector3 v4 = v1 - v2;
v4.display();
return 0;

}
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
16.3 常用运算符的重载
1.自增自减:

//前置运算符 ++a --a
operator++()
operator–()
operator++(Vector3 &v)
operator–(Vector3 &v)
//后置运算符 a-- a++
operator++(int)
operator–(int)
operator++(Vector3 &v,int)
operator–(Vector3 &v,int)
1
2
3
4
5
6
7
8
9
10
2.赋值运算符:

String& String::operator=(String &s)
{
if(this!=&s)
{
delete[] str;
int length = strlen(s.str);
str = new char[length+1];
strcpy(str,s.str);
}
return (*this)
}
1
2
3
4
5
6
7
8
9
10
11
3.输入\输出运算符重载

friend ostream &operator<<( ostream &output,
const Vector3 &v )
{
output << "F : " <<v.m_x<< " I : " << v.m_y<<v.m_z;
return output;
}

  friend istream &operator>>( istream  &input, Vector3 &v )
  { 
     input >> v.m_x>> v.m_y>>v.m_z;
     return input;            
  }

1
2
3
4
5
6
7
8
9
10
11
12
16.4 实现类型转换
不指定函数类型和参数,返回值的类型由类型名来确定。
类型转换函数只能作为成员函数,不能作为友元函数。
类型转换函数的一般形式:
operator 类型名()
{
转换语句;
}
class Vector3
{
public:
Vector3();
Vector3(double x,double y,double z);
public:
Vector3 operator+(const Vector3 &A)const;
Vector3 operator++();
friend Vector3 operator-(const Vector3 &v1, const Vector3 &v2);
friend Vector3 operator–(Vector3 &v,int);
operator double()
{
return m_x + m_y + m_z;
}
void display()const;
private:
double m_x;
double m_y;
double m_z;
};
int main()
{
Vector3 v1(1, 2, 3);
double d = v1;
cout << d << endl;//6
return 0;
}
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
17 IO流
流-一连串连续不断的数据集合。

17.1 流类和对象
输入流-从输入设备流向内存的流。
输出流-从内存流出设备的流。
内存缓冲区-用来存放流中的数据。
输入输出流程:键盘输入=》键盘缓冲区=(回车触发)》程序的输入缓冲区=》‘>>’提取数据
输出缓冲区=(缓冲满或endl)》‘<<’送到 显示器显示
输入/输出流类:
iostream:ios ,istream,ostream,iostream
fstream:ifstream,ofstream,fstream
strstream:istrstream,ostrstream,strstream

istream 是用于输入的流类,cin 就是该类的对象。
ostream 是用于输出的流类,cout 就是该类的对象。
ifstream 是用于从文件读取数据的类。
ofstream 是用于向文件写入数据的类。
iostream 是既能用于输入,又能用于输出的类。
fstream 是既能从文件读取数据,又能向文件写入数据的类。
istrstream 输入字符串类
ostrstream 输出字符串类
strstream 输入输出字符串流类
在这里插入图片描述
17.2 标准输入输出流
C++的输入/输出流库(iostream)中定义了4个标准流对象:cin(标准输入流-键盘),cout(标准输出流-屏幕),cerr(标准错误流-屏幕),clog(标准错误流-屏幕)

cerr 不使用缓冲区,直接向显示器输出信息;而输出到 clog 中的信息会先被存放到缓冲区,缓冲区满或者刷新时才输出到屏幕。
cout 是 ostream 类的对象,ostream 类的无参构造函数和复制构造函数都是私有的,所以无法定义 ostream 类的对象。
使用>>提取数据时,系统会跳过空格,制表符,换行符等空白字符。所以一组变量输入值时,可用这些隔开。
输入字符串,也是跳过空白字符,会在串尾加上字符串结束标志\0。
int x;
double y;
cin>>x>>y;
//输入 22 66.0 两个数之间可以用空格、制表符和回车分隔数据
char str[10];
cin>>str;//hei ren 字符串中只有hei\0
1
2
3
4
5
6
输入流中的成员函数

get函数:cin.get(),cin.get(ch)(成功返回非0值,否则返回0),cin.get(字符数组(或字符指针),字符个数n,终止字符)
char c = cin.get();//获取一个字符
while ((c = cin.get()) != EOF)//循环读取,直到换行
{
cout << c;
}

char ch;
cin.get(ch);
while (cin.get(ch))//读取成功循环
{
cout << ch;
}

char arr[5];
cin.get(arr, 5, ‘\n’);//输入 heiren 结果 heir\0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
getline函数:cin.getline(字符数组(或字符指针),字符个数n,终止标志字符)
读取字符知道终止字符或者读取n-1个字符,赋值给指定字符数组(或字符指针)
char arr0[30],arr1[30],arr2[40];
cin>>arr0;//遇到空格、制表符或回车结束 “Heiren”
cin.getline(arr1,30);//字符数最多为29个,遇到回车结束 " Hello World"
cin.getline(arr2,40,’’);//最多为39个,遇到结束 “yar”
//输入 Heiren Hello World
//yar*123
1
2
3
4
5
6
cin.peek() 不会跳过输入流中的空格、回车符。在输入流已经结束的情况下,cin.peek() 返回 EOF。
ignore(int n =1, int delim = EOF)
int n;
cin.ignore(5, ‘Y’);//跳过前5个字符或Y之前的字符,‘Y’优先
cin >> n;
//输入1234567 -> 67 1234567Y345->345

//输入2020.2.23
int year,month,day;
cin >> year ;
cin.ignore() >> month ; //用ignore跳过 ‘.’
cin.ignore() >> day;
cin.ignore(); //跳过行末 ‘\n’

cout<< setfill(‘0’) << setw(2) << month ;//设置填充字符’\0’,输出宽度2
cout << “-” << setw(2) << day << “-” << setw(4) << year << endl;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
putback(char c),可以将一个字符插入输入流的最前面。
输出流对象

插入endl-输出所有数据,插入换行符,清空缓冲区
\n-输出换行,不清空缓冲区
cout.put(参数) 输出单个字符(可以时字符也可以是ASII码)
格式化输出
iomanip 中定义的流操作算子:

*不是算子的一部分,星号表示在没有使用任何算子的情况下,就等效于使用了该算子,例如,在默认情况下,整数是用十进制形式输出的,等效于使用了 dec 算子
流操纵算子 作 用
*dec 以十进制形式输出整数 常用
hex 以十六进制形式输出整数
oct 以八进制形式输出整数
fixed 以普通小数形式输出浮点数
scientific 以科学计数法形式输出浮点数
left 左对齐,即在宽度不足时将填充字符添加到右边
*right 右对齐,即在宽度不足时将填充字符添加到左边
setbase(b) 设置输出整数时的进制,b=8、10 或 16
setw(w) 指定输出宽度为 w 个字符,或输人字符串时读入 w 个字符
setfill© 在指定输出宽度的情况下,输出的宽度不足时用字符 c 填充(默认情况是用空格填充)
setprecision(n) 设置输出浮点数的精度为 n。在使用非 fixed 且非 scientific 方式输出的情况下,n 即为有效数字最多的位数,如果有效数字位数超过 n,则小数部分四舍五人,或自动变为科学计 数法输出并保留一共 n 位有效数字。在使用 fixed 方式和 scientific 方式输出的情况下,n 是小数点后面应保留的位数。
setiosflags(flag) 将某个输出格式标志置为 1
resetiosflags(flag) 将某个输出格式标志置为 0
boolapha 把 true 和 false 输出为字符串 不常用
*noboolalpha 把 true 和 false 输出为 0、1
showbase 输出表示数值的进制的前缀
*noshowbase 不输出表示数值的进制.的前缀
showpoint 总是输出小数点
*noshowpoint 只有当小数部分存在时才显示小数点
showpos 在非负数值中显示 +
*noshowpos 在非负数值中不显示 +
*skipws 输入时跳过空白字符
noskipws 输入时不跳过空白字符
uppercase 十六进制数中使用 A~E。若输出前缀,则前缀输出 0X,科学计数法中输出 E
*nouppercase 十六进制数中使用 a~e。若输出前缀,则前缀输出 0x,科学计数法中输出 e。
internal 数值的符号(正负号)在指定宽度内左对齐,数值右对 齐,中间由填充字符填充。
流操作算子使用方法:cout << hex << 12 << “,” << 24;//c,18
setiosflags() 算子
setiosflags() 算子实际上是一个库函数,它以一些标志作为参数,这些标志可以是在 iostream 头文件中定义的以下几种取值,它们的含义和同名算子一样。

标 志 作 用
ios::left 输出数据在本域宽范围内向左对齐
ios::right 输出数据在本域宽范围内向右对齐
ios::internal 数值的符号位在域宽内左对齐,数值右对齐,中间由填充字符填充
ios::dec 设置整数的基数为 10
ios::oct 设置整数的基数为 8
ios::hex 设置整数的基数为 16
ios::showbase 强制输出整数的基数(八进制数以 0 开头,十六进制数以 0x 打头)
ios::showpoint 强制输出浮点数的小点和尾数 0
ios::uppercase 在以科学记数法格式 E 和以十六进制输出字母时以大写表示
ios::showpos 对正数显示“+”号
ios::scientific 浮点数以科学记数法格式输出
ios::fixed 浮点数以定点格式(小数形式)输出
ios::unitbuf 每次输出之后刷新所有的流
ios::stdio 每次输出之后清除 stdout, stderr
多个标志可以用|运算符连接,表示同时设置。例如:
cout << setiosflags(ios::scientific|ios::showpos) << 12.34;//+1.234000e+001
1
如果两个相互矛盾的标志同时被设置,结果可能就是两个标志都不起作用,应该用 resetiosflags 清除原先的标志
cout << setiosflags(ios::fixed) << 12.34 << endl;
cout << resetiosflags(ios::fixed) << setiosflags(ios::scientific | ios::showpos) << 12.34 << endl;
1
2
ostream 类中的成员函数:

成员函数 作用相同的流操纵算子 说明
precision(n) setprecision(n) 设置输出浮点数的精度为 n。
width(w) setw(w) 指定输出宽度为 w 个字符。
fill© setfill © 在指定输出宽度的情况下,输出的宽度不足时用字符 c 填充(默认情况是用空格填充)。
setf(flag) setiosflags(flag) 将某个输出格式标志置为 1。
unsetf(flag) resetiosflags(flag) 将某个输出格式标志置为 0。
setf 和 unsetf 函数用到的flag,与 setiosflags 和 resetiosflags 用到的完全相同。
cout.setf(ios::scientific);
cout.precision(8);
cout << 12.23 << endl;//1.22300000e+001

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值