Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.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++ - Fatal编程技术网

C++ 虚拟函数的动态绑定

C++ 虚拟函数的动态绑定,c++,C++,嗨, 我对这里的动态绑定有疑问。因为编译器知道当b.foo存在时,它可以使用基本虚函数。当存在d.foo时,它可以使用foo的派生版本。我的意思是,编译器在编译时拥有每一点信息,但仍然有文献说,将使用哪个函数是在运行时决定的 您是说编译器可以注意到您将d强制转换为Base*ptr,并在运行时解析实际的函数地址吗 如果是,样本在哪里: class base { public: virtual void foo() { cout << "Base cla

嗨,
我对这里的动态绑定有疑问。因为编译器知道当b.foo存在时,它可以使用基本虚函数。当存在d.foo时,它可以使用foo的派生版本。我的意思是,编译器在编译时拥有每一点信息,但仍然有文献说,将使用哪个函数是在运行时决定的

您是说编译器可以注意到您将d强制转换为Base*ptr,并在运行时解析实际的函数地址吗

如果是,样本在哪里:

class base {
public:
    virtual void foo()
    {
         cout << "Base class virutal function " << endl;
     }
}

class Derived : public base {
public:
    void foo()
     {
          cout << "Derived class virtual function " << endl;


int main()
{
    Base b, *ptr;
    Derived d;

    ptr = &b;
    ptr->foo();
    ptr = &d;
    ptr->foo();
}

编译器如何在运行时知道地址?这就是动态绑定存在的原因。

您是说编译器可以注意到您将d强制转换为Base*ptr,并在运行时解析实际的函数地址吗

如果是,样本在哪里:

class base {
public:
    virtual void foo()
    {
         cout << "Base class virutal function " << endl;
     }
}

class Derived : public base {
public:
    void foo()
     {
          cout << "Derived class virtual function " << endl;


int main()
{
    Base b, *ptr;
    Derived d;

    ptr = &b;
    ptr->foo();
    ptr = &d;
    ptr->foo();
}
编译器如何在运行时知道地址?这就是动态绑定存在的原因。

在这种特定情况下1,编译器至少在理论上可以确定在每种情况下调用哪个函数,并生成代码直接调用这两个函数。当我对其进行测试时,大多数编译器都会以这种方式优化代码

多态性的一个更典型的情况是涉及某种用户输入,因此不能静态地确定要调用的函数。例如,使用基类和派生类,请考虑类似:

if (rand() > 0.5)
{
    ptr = &b;
}
else
{
    ptr = &d;
}

ptr->foo();
在这种情况下,编译器无法确定静态调用的正确函数——根据运行命令行时在命令行上传递的内容,它可能使用foo的基本版本或派生版本

您似乎也有一种中间情况,您开始尝试在代码中包含,但从未真正完成-您初始化ptr以指向基本对象,然后指向派生对象,但您从未通过ptr调用函数,仅直接对对象本身进行调用。如果您确实通过指针调用函数,那么与仅直接处理具体对象相比,优化将更加困难。在这种情况下,较少的编译器将静态地确定类型,但至少有些编译器仍然可以/将这样做

1不管怎么说,这几乎是一个特殊的案例。目前,代码不会编译,因为您已经定义了一个名为基本小写字母“b”的类,并试图实例化一个名为基本大写字母“b”的类。此外,您的派生类实际上并不像您想象的那样从Base派生。一旦这些函数被修复,在这种特定的情况下,编译器至少在理论上可以确定在每种情况下调用哪个函数,并生成代码直接调用这两个函数,当我对其进行测试时,大多数编译器将以这种方式优化代码

多态性的一个更典型的情况是涉及某种用户输入,因此不能静态地确定要调用的函数。例如,使用基类和派生类,请考虑类似:

if (rand() > 0.5)
{
    ptr = &b;
}
else
{
    ptr = &d;
}

ptr->foo();
在这种情况下,编译器无法确定静态调用的正确函数——根据运行命令行时在命令行上传递的内容,它可能使用foo的基本版本或派生版本

您似乎也有一种中间情况,您开始尝试在代码中包含,但从未真正完成-您初始化ptr以指向基本对象,然后指向派生对象,但您从未通过ptr调用函数,仅直接对对象本身进行调用。如果您确实通过指针调用函数,那么与仅直接处理具体对象相比,优化将更加困难。在这种情况下,较少的编译器将静态地确定类型,但至少有些编译器仍然可以/将这样做


1不管怎么说,这几乎是一个特殊的案例。目前,代码不会编译,因为您已经定义了一个名为基本小写字母“b”的类,并试图实例化一个名为基本大写字母“b”的类。此外,您的派生类实际上并不像您想象的那样从Base派生。一旦这些问题得到解决……

在这里给出的具体示例中,您是正确的;编译器有足够的信息知道在编译时调用哪个函数。因此,编译器不必在运行时查找函数,但这是一种编译器优化,不会影响程序的结果-编译器可以自由绕过查找或不绕过查找。

在这里给出的特定示例中,您是正确的;编译器有足够的信息知道在编译时调用哪个函数。因此,编译器不必在运行时查找函数,但这是一种编译器优化,不会影响程序的结果-编译器可以自由绕过查找或不绕过查找。

您的意思是将派生类作为基类的子类吗?我没有看到继承…你确定你不想使用ptr->foo;某处?派生::foo是私有的!!!您的意思是将派生类作为基类的子类吗?我没有看到继承…你确定你不想使用ptr->foo;在什么地方
ived::foo是私人的!!!我删除了我的答案,因为弗雷德·拉森向我指出了同样的错误逻辑。我删除了我的答案,因为弗雷德·拉森向我指出了同样的错误逻辑。呼叫在对象上,没有通过指针。很抱歉,我在匆忙中犯了错误。我已经编辑过了。现在,在本例中,编译器有足够的信息来调用哪个foo,其中是动态绑定here@user634615:该行为是动态绑定的行为。如果编译器有足够的信息,它可以优化操作,但它必须保证结果与运行时发生动态绑定时的结果相同。很抱歉,我在匆忙中犯了错误。我已经编辑过了。现在,在本例中,编译器有足够的信息来调用哪个foo,其中是动态绑定here@user634615:该行为是动态绑定的行为。如果编译器有足够的信息,它可以优化操作,但是它必须保证结果与动态绑定在运行时发生的结果相同。