Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 不同场景下的虚拟关键字_C++_Virtual - Fatal编程技术网

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-
完全无关第一航空公司