前面的笔记里介绍了常用的一些运算符的重载,这里再介绍一些需要知道的运算符的重载。
下标操作符[ ]
语法形式:
一般都有两种方式,为了语义一致,对一个常量取其一个元素,也是不能通过这个元素更改常量,对一个变量取其元素,通常是可以修改其值
返回类型 operator[](size_t i);
const 返回类型 operator[](size_t i)const;
#include <iostream>
using namespace std;
class Array{
//表示一个容器,里面可以放若干个整型数
public:
Array(size_t size){
p_m_data = new int[size];
}
~Array(void){
delete[] p_m_data;
p_m_data = NULL;
}
int &operator[](size_t i){
return p_m_data[i];
}
const int &operator[](size_t i)const{
return p_m_data[i];
}
private:
int *p_m_data;
};
int main(void){
Array const arr(10);
for (int i = 0; i < 10; i++ ){
//arr[i] = i + 1;
cout << arr[i] << ' ' ;
}
cout << endl;
return 0;
}
函数调用操作符()
语法形式:
返回值类型 operator()(参数列表){}
用的很少,可以让对象变得和调用函数一样,可读性差
#include <iostream>
using namespace std;
class Func{
public:
double operator()(double d){
return d * d;
}
private:
};
int main(void){
Func f;
cout << f(10.0) << endl;
return 0;
}
new/delete操作符
这两个也是可以被重载的,但是基本不会去重载它们。
这里需要知道的是,当通过new和delete操作对象的时候,是先创建内存空间,然后再调用构造函数,而释放的时候,是先调用析构函数,然后再销毁空间。
当一个类,只有成员函数,没有成员变量的时候,它至少拥有一个字节的大小,这是语法规定。
1) 不是所有的操作附都能重载
–>作用域限定操作附 ::
–>直接成员访问操作附 .
–>直接成员指针解引用操作附 .*
–>条件操作附 ? :
–>字节长度操作附 sizeof
–>类型信息操作附 typeid
2) 如果一个操作附所有的操作数都是基本类型,则无法重载
3) 操作附重载不会改变编译器预定义的优先级
4) 操作附重载无法改变操作数的个数
5) 无法通过操作附重载发明新的操作附
继承
向上造型:
可以通过父类类型的指针去访问一个子类类型的对象。可以想象成父类是子类的一个子集,当使用父类类型的指针访问子类类型的对象的时候,一定不会存在越界的行为。编译器认为这种隐式(从子类类型指针转换成父类类型指针)的转换是安全的。所以可以这么使用。但是,仅仅只适用于public方式继承的子类。
ps:
son s1;
father *p_f = & s1;
向下造型:
将父类类型的指针或者引用,转换成子类类型的指针或者引用。子类可能拥有父类不具备的成员,这个时候通过该指针访问,会出现越界行为,在编译器看来是不安全的,不支持这样的隐式转换。但是,可以通过静态类型转换static_cast进行强制转换。
ps:
father f1;
son *p_s = & f1;
继承方式和访问控制
两者决定了子类从父类继承的成员在子类中的访问控制属性。
基类成员 共有继承 保护继承 私有继承
public: public protected private
protecter: protected protected private
private: private private private
————————————————————————————
二十、操作附重载
1、 双目
2、 单目
3、 <<、>>
4、 下标操作附[]
功能:让一个对象能够像数组一样去使用
注:非常对象返回左值,常对象返回右值
string s = “hlleo”;
s[0] = ‘H’;
5、 函数调用操作附()
功能:让对象像函数一样使用
注:对参数的个数、类型和返回值类型没有任何限制
class A{};
A a;
a(100,200);//a.operator(100,200);
6、new\delete操作附
static void *operator new(size_t size){…}
static void operator delete(void *pv){…}
类中没有成员变量,只有成员函数的时候,对象的大小,至少有一个字节
7、操作附重载的限制
1) 不是所有的操作附都能重载
–>作用域限定操作附 ::
–>直接成员访问操作附 .
–>直接成员指针解引用操作附 .*
–>条件操作附 ? :
–>字节长度操作附 sizeof
–>类型信息操作附 typeid
2) 如果一个操作附所有的操作数都是基本类型,则无法重载
3) 操作附重载不会改变编译器预定义的优先级
4) 操作附重载无法改变操作数的个数
5) 无法通过操作附重载发明新的操作附
二十一、继承
1、 继承的概念
通过一种机制来表达类型之间共性和特性的方式。利用已有的数据类型来定义新的数据类型,这种机制就是继承。
eg:
学生类:姓名、年龄、学号、吃饭、睡觉、学习
教师类:姓名、年龄、工资、吃饭、睡觉、讲课
人类:姓名、年龄、吃饭、睡觉
学生类继承人类:学号、学习
教师类继承人类:工资、讲课
人类(基类,父类)
/ \
学生类 教师类(派生类,子类)
基类-->派生-->子类
子类-->继承-->基类
2、 继承的语法
class 子类:继承方式1 基类1,继承方式2 基类2,…{}
继承方式:public、protected、private
–共有继承(public)
–保护继承(protected)
–似有继承(private)
3、共有继承的特性(public)
1) 子类继承基类的属性和行为,通过子类对象,可以访问基类中的成员,如同是基类对象在访问它们一样。
2) 向上造型
将子类类型的指针或者引用转换为基类类型的指针或引用。
注:向上造型,是操作性缩小的类型转换,在编译器看来是安全的,可以隐士完成。
基类
子类
3) 向下造型
将基类类型的指针或引用转换为子类类型的指针或引用
注:向下造型,数据操作性扩大的类型装欢,在编译器看来是危险的,仅需要现实完成。
4) 子类继承基类的成员
–>在子类中,可以直接访问基类中的公有成员和保护成员,就如同他们是子类的成员一样
–>基类的私有成员,可以被子类继承,但是子类无法直接访问。如果需要访问,可以通过基类提供的公有或保护的成员函数来间接的访问。
–>基类的构造函数,和析构函数,子类是无法继承的。但是可以在子类的构造函数初始化表中,指明基类部分(基类子对象)的初始化方式
5) 子类隐藏基类的成员(局部变量隐藏全局变量,有点类似,但是不一样)
–>子类和基类中,如果定义了同名的成员函数,因为作用域不同,不能构成重载关系,而是一种隐藏关系。
–>如果需要通过子类访问到基类中隐藏的成员,可以通过类名作用域限定的方式来显式指明,对象.基类::基类成员
–>通过using声明可以将基类成员函数引入到子类作用域范围内,形成重载,不建议使用。
4、 继承方式和访问控制
1) 访问控制限定符:影响访问该类成员位置
限定符 访问控制 内部 子类 外部 友元
public: 公有成员 ok ok ok ok
protected: 保护成员 ok ok no ok
private: 私有成员 ok no no ok
2) 继承方式:子类对基类中成员的可访问性
基类成员 共有继承 保护继承 私有继承
public: public protected private
protecter: protected protected private
private: private private private
注:向上造型不适用于私有继承,保护继承