目录
1,虚函数
如果类中包含虚函数(virtual),那么对象的首地址就是一个虚函数表,表中是一系列虚函数指针,每一个指向一个虚函数。
如果基类的函数被定义为虚函数(virtual),那么派生类中重定义的函数也都自动是虚函数,不用加virtual
虚函数允许用基类类型的指针,调用子类的这个函数。
PS:如果基类中的不是虚函数,派生类中也可以定义为虚函数,不过一般估计不会这么做。
2,重载、重写、覆盖
函数重载overload,是多个函数名字相同,但签名不同,既适用于普通函数之间,也适用于同一个类的成员函数之间,无论是构造函数还是普通成员函数,但不用于析构函数。
函数重写override,也叫函数重定义,指的是在派生类中重定义基类的虚函数,重定义的函数和基类函数具有相同签名,无论是构造函数、析构函数还是普通成员函数,都可以重定义。
函数覆盖hide,指的是在派生类中重定义基类的非虚函数,重写可以实现多态,覆盖不能。
示例:
#include<iostream>
using namespace std;
class C
{
public:
string toString()
{
return "class C";
}
string toString(string x)
{
return "class C"+x;
}
};
class B:public C
{
public:
int toString()
{
return 0;
}
};
class A :public B
{
public:
string toString()
{
return "class A";
}
};
int main()
{
string s="abc";
cout << C().toString() << endl;
cout << C().toString(s) << endl;//函数重载
cout << B().toString() << endl;//函数重定义
cout << A().toString() << endl;//函数重定义
return 0;
}
输出结果:
class C
class Cabc
0
class A
如果函数重定义之后,派生类对象要调用基类函数,使用基类名和作用域解析运算符::
class B:public C
{
public:
int toString()
{
cout<<C::toString()<<endl;
return 0;
}
};
如果父类中的是非虚函数,子类中加virtual关键字,那么结果仍然是覆盖,非多态。
3,泛型程序设计
C++的泛型设计有好几种设计,普通函数的重载、运算符重载、类成员函数重载和重定义、多态,都属于泛型程序设计的范畴。
在程序中需要一个基类对象时,向其提供一个派生类对象是允许的。
这种特性使得一个函数可适用于较大范围的对象实参,这也是一种泛型程序设计,而这已经非常接近多态的用法了。
#include<iostream>
using namespace std;
class C
{
public:
string toString()
{
return "class C";
}
};
class B:public C
{
public:
string toString()
{
return "class B";
}
};
class A :public B
{
public:
string toString()
{
return "class A";
}
};
void display(C x)
{
cout << x.toString() << endl;
}
int main()
{
display(A());//泛型程序设计
display(B());
display(C());
return 0;
}
输出:
class C
class C
class C
4,多态
在上面的例子中,三次调用display函数,实际调用的都是C的toString函数。
要想实现每个对象调用自己类的函数,即实现多态,需要用虚函数和对象指针。
示例:
#include<iostream>
using namespace std;
class C
{
public:
virtual string toString()
{
return "class C";
}
};
class B:public C
{
public:
string toString()
{
return "class B";
}
};
class A :public B
{
public:
string toString()
{
return "class A";
}
};
void display(C *p)
{
cout << p->toString() << endl;
}
int main()
{
C* p= new A();
display(p);
p= new B();
display(p);
p= new C();
display(p);
return 0;
}
输出结果:
class A
class B
class C
用传引用的方式也可以实现多态:
void display(C& p)
{
cout << p.toString() << endl;
}
int main()
{
C* p= new A();
display(*p);
p= new B();
display(*p);
p= new C();
display(*p);
return 0;
}
用模板可以实现类似的功能:
template<typename T>
void display(T x)
{
cout << x.toString() << endl;
}
int main()
{
display(A());
display(B());
display(C());
return 0;
}
输出是一样的。
模板是编译期多态,虚函数多态是运行时多态。
5,虚析构函数
正常析构过程:
#include<iostream>
using namespace std;
class Person
{
public:
Person()
{
cout << "Person con" << endl;
}
~Person()
{
cout << "Person des" << endl;
}
};
class Employee:public Person
{
public:
Employee()
{
cout << "Employee con" << endl;
}
~Employee()
{
cout << "Employee des" << endl;
}
};
class Fac :public Employee
{
public:
Fac()
{
cout << "Fac con" << endl;
}
~Fac()
{
cout << "Fac des" << endl;
}
};
int main()
{
auto* fac=new Fac;
delete fac;
return 0;
}
输出:
Person con
Employee con
Fac con
Fac des
Employee des
Person des
这里的fac类型其实就是子类Fac类型。
异常析构过程:
int main()
{
Person* fac=new Fac;
delete fac;
return 0;
}
输出:
Person con
Employee con
Fac con
Person des
只调用了父类的析构函数。
这样很容易出错,毕竟把指向子类对象的指针类型设为父类类型是非常常用且重要的,
这种情况下为了避免new出来的对象delete不干净,可以把父类析构函数设为虚函数:
class Person
{
public:
Person()
{
cout << "Person con" << endl;
}
virtual ~Person()
{
cout << "Person des" << endl;
}
};
一般地,在不考虑极致性能的情况下,所有的析构函数都可以设为虚函数。
6,判断函数是否是虚函数、override
如果继承关系比较复杂,那么如何判断一个函数是不是虚函数呢?
方法一:利用结论 重写可以实现多态,覆盖不能
#include <iostream>
using namespace std;
class X
{
//unknown
};
class A:public X
{
public:
int f()
{
return 0;
}
};
class B:public A
{
public:
int f()
{
return 12345678;
}
};
int main() {
B b;
A* p = &b;
if(p->f()==b.f())cout<<"same, virtual function";
else cout<<"not same, not virtual function";
return 0;
}
方法二:利用关键字override或者final
只有虚函数可以用override修饰
#include<iostream>
using std::cout;
class X
{
//unknown
};
class A:public X
{
public:
int f() override
{
return 0;
}
};
int main()
{
return 0;
}
只要能编译过就说明A::f是虚函数
同理,用final也可以
7,final
(1)修饰函数
只有虚函数可以用final修饰,表示函数不能被重写
class A
{
public:
virtual int f() final
{
return 0;
}
};
class B: public A
{
int f()
{
return 0;
}
};
报错:Declaration of 'f' overrides a 'final' function
(2)修饰类
表示类不能被继承
class A final
{
public:
virtual int f()
{
return 0;
}
};
class B: public A
{
};
报错:Base 'A' is marked 'final'