类的继承——虚函数
● 通过虚函数与引用(指针)实现动态绑定
– 使用关键字 virtual 引入
– 非静态、非构造函数可声明为虚函数
– 虚函数会引入vtable结构
● dynamic_cast
static_cast, reinterpret_cast, const_cast在编译期发生。
dynamic_cast在运行期发生,即判断动态类型满不满足转换条件,如果不满足,不发生转换。运行开销大。
struct Base
{
virtual void baseMethod() {} //关键字virtual引入了vtable结构,vtable引入了typeinfo
int baseMember;
};
struct Derive : Base
{
virtual void deriveMethod() {} //关键字virtual引入了vtable结构,vtable引入了typeinfo
int deriveMember;
};
struct Derive2 : Derive
{
virtual void derive2Method() {} //关键字virtual引入了vtable结构,vtable引入了typeinfo
int derive2Member;
};
int main()
{
Derive2 d;
Base& b = d;
Base* ptr = &d;
Derive2& d2 = dynamic_cast<Derive2&>(b); //OK,因为typeinfo可以存储动态类型的信息
Derive2* ptr2 = dynamic_cast<Derive2*>(ptr); //OK,因为typeinfo可以存储动态类型的信息
return 0;
}
struct Base
{
//virtual void baseMethod() {}
int baseMember;
};
struct Derive : Base
{
//virtual void deriveMethod() {}
int deriveMember;
};
struct Derive2 : Derive
{
//virtual void derive2Method() {}
int derive2Member;
};
int main()
{
Derive2 d;
Base& b = d;
Base* ptr = &d;
Derive2& d2 = dynamic_cast<Derive2&>(b); //因为没有关键字virtual的非静态、非构造函数,所以不能引入vtable,进而不能引入typeinfo,Error: 'Base' is not polymorphic
Derive2* ptr2 = dynamic_cast<Derive2*>(ptr); //同上,Error: 'Base' is not polymorphic
return 0;
}
struct Base
{
virtual void baseMethod() {}
int baseMember;
};
struct Derive : Base
{
//virtual void deriveMethod() {}
int deriveMember;
};
struct Derive2 : Derive
{
//virtual void derive2Method() {}
int derive2Member;
};
int main()
{
Derive2 d;
Base& b = d;
Base* ptr = &d;
Derive2& d2 = dynamic_cast<Derive2&>(b); //只要基类中有一个virtual函数就可以
Derive2* ptr2 = dynamic_cast<Derive2*>(ptr); //同上
return 0;
}
struct Base
{
virtual void baseMethod() {}
int baseMember;
};
struct Derive : Base
{
virtual void deriveMethod() {}
int deriveMember;
};
struct Derive2 : Derive
{
virtual void derive2Method() {}
int derive2Member;
};
int main()
{
Base b;
Base& bb = b; //#3: 基类类型的引用bb引用基类对象b
Base* ptrb = &b; //#1: 基类类型的指针ptrb指向基类对象b
std::cout << dynamic_cast<Derive2*>(ptrb) << std::endl; //如果#1,将ptrb用dynamic_cast转换为派生类类型的指针,dynamic_cast会返回空指针
//std::cout << dynamic_cast<Derive2&>(bb) << std::endl; //如果#3,将bb用dynamic_cast转换为派生类类型的引用,dynamic_cast会抛出异常
Derive2 d2;
Base& bd = d2; //#4: 基类类型的引用bb引用派生类对象d2
Base* ptrd = &d2; //#2: 基类类型的指针ptrd指向派生类对象d2
Derive2* d2ptr = dynamic_cast<Derive2*>(ptrd);
Derive2& d2ref = dynamic_cast<Derive2&>(bd);
std::cout << std::is_same_v<decltype(d2ptr), Derive2*> <<std::endl; //如果#2,将ptrd用dynamic_cast转换为派生类类型的指针,dynamic_cast会转换成功返回派生类类型的指针
std::cout << std::is_same_v<decltype(d2ref), Derive2&> <<std::endl; //如果#4,将bd用dynamic_cast转换为派生类类型的引用,dynamic_cast会转换成功返回派生类类型的引用
return 0;
}
● 虚函数在基类中的定义
– 引入缺省逻辑
– 可以通过 = 0 声明纯虚函数,相应地构造抽象基类
● 虚函数在派生类中的重写( override )
struct Base
{
void fun() //无virtual关键字
{
std::cout << "void Base::fun()\n";
}
};
struct Derive : Base
{
void fun()
{
std::cout << "void Derive::fun()\n";
}
};
int main()
{
Derive d;
d.fun(); //调用Derive::fun()
Base& b = d;
b.fun(); //调用Base::fun()
return 0;
}
struct Base
{
virtual void fun() //有virtual关键字
{
std::cout << "virtual void Base::fun()\n";
}
};
struct Derive : Base
{
void fun()
{
std::cout << "void Derive::fun()\n";
}
};
int main()
{
Derive d;
d.fun(); //调用Derive::fun()
Base& b = d;
b.fun(); //调用Derive::fun()
return 0;
}
struct Base
{
virtual void fun() //有virtual关键字
{
std::cout << "virtual void Base::fun()\n";
}
};
struct Derive : Base
{
void fun() //函数签名与基类中的虚函数void fun()相同,是后者在派生类中的重写(override)
{
std::cout << "void Derive::fun()\n";
}
};
void proc(Base& b) //传入的参数类型不一样
{
b.fun(); //内部逻辑会表现出不同的行为,称为动态多态(也叫运行期多态(即通过动态类型实现的运行期的多态)),其基础就是virtual
}
int main()
{
Base b; //b的静态类型和动态类型都是Base
proc(b); //调用Base::fun()
Derive d; //动态类型是Derive
proc(d); //调用Derive::fun()
return 0;
}
– 函数签名保持不变(返回类型可以是原始返回指针 / 引用类型的派生指针 / 引用类型)
struct Base2 {};
struct Derive2 : Base2 {};
struct Base
{
virtual Base2* fun()
{
std::cout << "virtual Base2* Base::fun()\n";
static Base2 b2;
return &b2;
}
};
struct Derive : Base
{
Derive2* fun() //即使返回类型不同也构成重写
//Derive2& fun() //Error: Virtual function 'fun' has a different return type ('Derive2 &') than the function it overrides (which has return type 'Base2 *')
{
std::cout << "Derive2* Derive::fun()\n";
static Derive2 d2;
return &d2;
}
};
void proc(Base& b)
{
b.fun();
}
int main()
{
Base b;
proc(b); //OK
Derive d;
proc(d); //OK
return 0;
}
struct Base2 {};
struct Derive2 : Base2 {};
struct Base
{
virtual void fun()
{
std::cout << "virtual void Base::fun()\n";
}
};
struct Derive : Base
{
void fun(int) //参数列表不同,与继承自Base中的virtual void fun()构成重载
//int fun() //Error: Virtual function 'fun' has a different return type ('int') than the function it overrides (which has return type 'void')
{
std::cout << "void Derive::fun(int)\n";
//return 3;
}
};
void proc(Base& b)
{
b.fun();
}
int main()
{
Base b;
proc(b); //OK
Derive d;
proc(d); //OK
return 0;
}
struct Base
{
virtual void fun() = 0; //纯虚函数,不需要给出一个实现,在vtable指向的地方开了一个槽但是并不指向任何的东西
//例如:triangle继承自shape,right triangle继承自triangle,triangle和right triangle都可以画出形状,但不能画出shape的形状
};
struct Derive : Base
{
void fun()
{
std::cout << "void Derive::fun()\n";
}
};
void proc(Base& b)
{
b.fun();
}
int main()
{
Derive d;
Base* ptr = &d;
Base& ref = d;
proc(*ptr); //OK
proc(ref); //OK
return 0;
}
struct Base
{
virtual void fun() = 0;
};
struct Derive : Base
{
void fun()
{
std::cout << "void Derive::fun()\n";
}
};
struct Derive2 : Base
{
//Derive2中并没有重写基类中的virtual void fun() = 0,因此Derive2也是一个抽象基类
};
void proc(Base& b)
{
b.fun();
}
int main()
{
Derive2 d; //Error: Variable type 'Derive2' is an abstract class
return 0;
}
struct Base
{
virtual void fun() = 0;
};
struct Derive : Base
{
void fun() //重写
{
std::cout << "void Derive::fun()\n";
}
};
struct Derive2 : Derive
{
//Derive2的公有成员中有继承自Derive的void fun(),不是抽象基类
};
void ptrProc(Base* b)
{
b->fun();
}
void refProc(Base& b)
{
b.fun();
}
int main()
{
Derive2 d;
ptrProc(&d); //OK
refProc(d); //OK
return 0;
}
struct Base
{
virtual void fun() = 0
{
} //原因尚待求索,Semantic Issue: Initializer on function does not look like a pure-specifier
};
struct Base
{
virtual void fun() = 0;
};
void Base::fun() //应用场景非常少,但技术上是可以的,但并不改变Base是一个抽象基类,所以不能定义Base类对象
{
std::cout << "Defination of virtual void Base::fun() = 0 out of class OK\n";
}
struct Derive : Base
{
void fun()
{
std::cout << "void Derive::fun()\n";
}
//相应地,如果派生类中没有定义重写逻辑,那派生类仍是一个抽象基类
};
void ptrProc(Base* b)
{
b->fun();
}
void refProc(Base& b)
{
b.fun();
}
int main()
{
Derive d;
ptrProc(&d); //OK
refProc(d); //OK
return 0;
}
struct Base
{
virtual void fun() = 0;
};
void Base::fun() //纯虚函数的一些辅助逻辑
{
std::cout << "Defination of virtual void Base::fun() = 0 out of class OK\n";
}
struct Derive : Base
{
void fun()
{
Base::fun(); //显式调用
std::cout << "void Derive::fun()\n";
}
};
void ptrProc(Base* b)
{
b->fun();
}
void refProc(Base& b)
{
b.fun();
}
int main()
{
Derive d;
ptrProc(&d); //OK
refProc(d); //OK
return 0;
}
– 虚函数特性保持不变
struct Base
{
virtual void fun()
{
std::cout << "virtual void fun()\n";
}
};
struct Derive : Base
{
void fun() //无virtual关键字
{
std::cout << "void Derive::fun()\n";
}
};
struct Derive2 : Derive
{
void fun() //无virtual关键字
{
std::cout << "void Derive2::fun()\n";
}
};
void ptrProc(Base* b)
{
b->fun();
}
void refProc(Base& b)
{
b.fun();
}
int main()
{
Base b;
ptrProc(&b);
refProc(b);
std::cout << '\n';
Derive d;
ptrProc(&d); //调用void Derive::fun()
refProc(d); //同上
std::cout << '\n';
Derive2 d2;
ptrProc(&d2); //调用void Derive::fun()
refProc(d2); //同上
std::cout << "\nTHIS IS DYNAMIC POLYMORPHISM (unable to std::cout Chinese in QT)\n";
return 0;
}
– override 关键字
struct Base
{
virtual void fun()
{
std::cout << "virtual void fun()\n";
}
};
struct Derive : Base
{
void fun(int) override //编译器会报错,方便代码调试 since C++11,Error: Non-virtual member function marked 'override' hides virtual member function
{
std::cout << "void Derive::fun()\n";
}
};
参考
深蓝学院: C++基础与深度解析
Virtual Function and Multilevel Inheritance