运算符重载与虚函数
单目运算符
接下来都以
AClass
作为一个类例子介绍
AClass{
int var
}
- 区分后置++与前置++
AClass operator ++ ()
++前置 一般设计为返回引用 这样的话可以将其作为左值(自然也可以作为右值,会调用该类的拷贝构造函数)++class = ...
AClass operator ++ (int)
后置++ 一般设计返回一个旧的类 获得的是历史版本,所含有的int
形参是用作区分类型的,并无实际含义- 由于一个__单变量__的构造函数可被视为__强制类型转换函数__
多目运算符
-
AClass & operator (const & Aclass a){ ... }
-
因此如果该类的构造函数满足把
int
变成这个类,你甚至可以这么写 -
int a; AClass A; A = A + a
函数的默认形参值只能写在声明里,不能写在定义里
- 对于
<<
的重载方式,定义友元函数 frend ostream & operator << (ostream & out, const ...)
- 这样
ostream
就能访问该类的私有成员了 - 注意!插入运算符
<<
的返回值要是这个out
的引用 {... return & out}
这样就可以实现一直<<
插入的神奇功能(请自己思考为什么, 提示:返回引用等于又把自己拿出来用了)
虚函数
覆盖 override 重载 overload
虚函数基本语法
巧妙的覆盖方式
- 虚函数的声明
virtual 函数类型 函数名(形参表){
函数内容}
- 可以在基类中声明虚函数,则子类中的相关函数会被同样被认为为虚函数
- 并且在创建基类指针指向一个子类时
- 调用该基类指针的这个虚函数
- 该指针会顺着找到子类的这个函数并且运行
- 体现了程序运行过程中的__动态多态特性__
- 例子
class Base{
virtual void func(){
cout << "Base" << endl;
}
}
class Base1{
void func(){
cout << "Base1" << endl;
}
}
class Base2: public base{
void func(){
cout << "Base2" << endl;
}
}
void display(base * ptr)
int main(){
Base1 b1;
Base2 b2;
Base * ptr1 = b1;
Base * ptr2 = b2;
display(ptr1);
display(ptr2);
}
/*
输出结果
Base1
Base2
*/
typeid
typeid(ptr).name()
此处ptr
为一个指针,返回这个指针的类型typeid(* ptr).name()
此处返回的是ptr
指向对象的类型- 如果你对上面的
ptr1 ptr2
进行第一种操作返回类型为base - 但是如果做第二种操作返回是base1和base2
虚析构函数
可能你想不到,析构函数也很虚
- 析构函数和构造函数是不会继承的
- 加上析构函数在组合关系中会按拓扑序反向调用
- 那么要虚构函数的理由就是有时候你需要动态删除由__基类指针指向的派生类__
- 没有虚函数你就只能把指针指向的东西__当成基类__,而其本身是__派生类__,进行了析构
- 那么这样子你就会漏去除一些内容
- 这样很不优雅(你可以想象内存会出现什么严重后果)
举个栗子!
- 比如我这么引用
Base *b = new Derived()
derived 代指派生类
- 那么我们的b一调用delete就凉凉了
delete b
- 编译器高兴地把b指向的地方当做Base删掉了
- 仔细想想,Derived的构造函数被调用了,但是析构函数被忽略了,(原因是我换了一个指针引用)
解决方法(就是虚析构函数)
- 给基类的析构函数前面加个virtual关键字
- 那么这就给这个东西加上了__动态多态性!__
- 然后编译器就会跑去先调用一下Derived类的析构函数然后再调用Base的
纯虚函数
很纯洁的函数
- 想想,概念都是完美的东西,那么纯虚函数就是用来描述概念的
纯虚函数语法
virtual 类型 函数名(参数列表) = 0
- 正如你所见,它没有函数体(非常的纯)
- 带有纯虚函数的类称之为__抽象类__(另一个叫做__具体类__)
抽象类
概念及理念
- 为啥需要抽象类
- 由于c++没有接口功能,那么这个纯虚函数便是用作接口功能
- 底下的派生类只有将所有纯虚函数全部实现才能称之为_具体类_
- 也可以用另一种观点来看,就是为所有派生类定义了规范
- 这是一种面向接口的设计方式,也是面向抽象类的设计
- 抽象类的设计需要非常谨慎,因为派生类需要围绕抽象类进行设计
- 那么如果没有设计好抽象类,那么容易带偏派生类
几个小规定
- 抽象类只能用作基类
- 不能声明抽象类的对象
- 原因:抽象类中具有纯虚函数,而这个函数按语法可调用,但是这个函数没有实现,因而为了解决这个问题直接禁止了抽象类的声明
- 构造函数不能够是虚函数,析构函数可以是虚函数
- 可以定义抽象类的指针