C++ 不同场景下的虚拟关键字
我找出了使用C++ 不同场景下的虚拟关键字,c++,virtual,C++,Virtual,我找出了使用virtual的两种不同情况 如果baseClass定义了一个函数virtual,则derivedClass将覆盖该函数 如果有任何类派生自virtual,则应定义baseClass::~baseClass()。这里的意思是,派生类销毁首先发生,然后是基类销毁 是否存在使用virtual的其他情况?virtual在应用于成员函数时始终具有相同的含义。当成员函数是虚拟的时,这意味着对该成员函数的调用将被动态调度 也就是说,将根据动态类型(实际类型)而不是静态类型来选择要调用的函数。
virtual
的两种不同情况
- 如果
定义了一个函数baseClass
,则virtual
将覆盖该函数derivedClass
- 如果有任何类派生自
,则应定义virtual
。这里的意思是,派生类销毁首先发生,然后是基类销毁baseClass::~baseClass()
是否存在使用
virtual
的其他情况?virtual
在应用于成员函数时始终具有相同的含义。当成员函数是虚拟的时,这意味着对该成员函数的调用将被动态调度
也就是说,将根据动态类型(实际类型)而不是静态类型来选择要调用的函数。根据对象的实际类型,将调用虚拟函数的最终重写器
析构函数“不同”的唯一原因是派生类析构函数的名称不同于基类析构函数。派生类析构函数的行为不受声明为virtual
的影响,但是:派生类析构函数总是在运行后调用基类析构函数
作为
虚拟
函数行为的示例:
struct B {
void f() { }
virtual void g() { }
};
struct D : B {
void f() { }
virtual void g() { }
};
int main() {
B* p = new D();
}
表达式*p
的动态类型是D
,因为p
指向的对象的实际类型是D
。您使用了newd()
来创建它,因此它的动态类型是D
表达式*p
的静态类型是B
,因为这是代码中指定的类型。如果不运行程序或评估分配给p
的内容,编译器就不知道*p
给出的对象的最派生类型;它只知道不管它是什么,它都是一个B
或从B
派生出来的东西
如果调用p->f()
,调用将静态调度,因为B::f
不是virtual
。编译器查看*p
的静态类型,并根据该类型选择要调用的函数(B::f
)
如果调用
p->g()
,则会动态调度调用,因为B::g
是虚拟的。在运行时,检查对象的动态类型(在许多常见实现中使用vtable),并调用最终重写器。在这种情况下,最后的重写器是D::g
,因为D
是重写B::g
的最派生类(如果有另一个类派生自D
,它也可以选择重写B::g
。还有虚拟继承,其中基类由间接引用
还要阅读C++-FAQ:虚拟继承是一个大问题。除其他事项外,它解决了多重继承引入的重复成员问题。谷歌“可怕的钻石图案”获取详细信息。虚拟继承示例
class UltimateBase{};
class Base1 : public virtual UltimateBase{};
class Base2 : public virtual UltimateBase {};
class Derived : public Base1, public Base2{};
因此,派生的
类的实例可能只有一个UltimateBase
类的子对象。假设您有一个类,您希望成为java、c#、php和actionscript之类的抽象类,但这个类没有纯虚拟方法。然后,您可以在类声明中将析构函数声明为纯虚方法,但仍然实现它。下面是一个例子:
#include <iostream>
class MyAbstractClass
{
public:
MyAbstractClass(int i);
virtual ~MyAbstractClass() = 0;
int getI() const;
private:
int m_i;
};
class MyConcreteClass : public MyAbstractClass
{
public:
MyConcreteClass(int i);
~MyConcreteClass();
};
MyAbstractClass::MyAbstractClass(int i) :
m_i(i)
{
std::cout << "constructor of MyAbstractClass\n";
}
MyAbstractClass::~MyAbstractClass()
{
std::cout << "destructor of MyAbstractClass\n";
}
int MyAbstractClass::getI() const
{
return m_i;
}
MyConcreteClass::MyConcreteClass(int i) :
MyAbstractClass(i)
{
std::cout << "constructor of MyConcreteClass\n";
}
MyConcreteClass::~MyConcreteClass()
{
std::cout << "destructor of MyConcreteClass\n";
}
int main(int argc, char* argv[])
{
MyConcreteClass a(5);
std::cout << a.getI();
std::cout << std::endl;
MyAbstractClass b(5); //compile error, can't instantiate a class with abstract functions
return 0;
}
#包括
类MyAbstractClass
{
公众:
MyAbstractClass(int i);
virtual~MyAbstractClass()=0;
int getI()常量;
私人:
国际货币基金组织;
};
类MyConcreteClass:公共MyAbstractClass
{
公众:
MyConcreteClass(inti);
~MyConcreteClass();
};
MyAbstractClass::MyAbstractClass(int i):
m_i(i)
{
std::cout关键字virtual
为函数提供后期绑定。在后期绑定中,函数调用直到运行时才绑定到任何对象。在多态性和运行时,类查找其v表以确定要调用的重载函数。当其类为多态性时,析构函数通常为virtual
。virtuall
可能与内联
最为相反,并且(至少在我看来)与extern
非常相似。Mahesh:不。静态类型和动态类型只能在有引用或指针时有所不同。静态类型总是它在代码中所说的。如果你说基类*p=new-DerivedClass()
,*p
的静态类型是基类
,因为这就是它在代码中所说的。然而,*p
的动态类型是派生类
,因为这是对象的实际类型。如果您只是有一个对象没有通过指针或引用访问,那么静态类型和动态类型必须是相同:给定BaseClass x;
,x
的类型总是BaseClass
,句号。@Mahesh:我试图添加更详细的解释。(不过,随着这个答案越来越长,它包含不准确或不正确信息的可能性越来越大;如果有人有任何更正或建议,请留下评论并让我知道。我相信其他人也可以提供更清楚的解释;如果是这样,我很乐意投票支持它。)没有“两种不同的含义”在你描述的情况下。在这两种情况下工作的机制完全相同,可以是析构函数或任何其他虚拟函数。到目前为止,你只有一个意思。你想做什么?顺便说一句,派生销毁总是在基础销毁之前发生。这与f中的virtual
@AndreyT-完全无关第一航空公司