【问题标题】:How can an object type be unknown at compile time?编译时如何不知道对象类型?
【发布时间】:2013-08-23 03:14:11
【问题描述】:

我目前正在学习动态绑定和虚函数。这是来自 Accelerated C++,第 13 章:

[...] 我们希望在运行时做出决定。也就是说,我们想要 系统根据实际类型运行正确的功能 传递给函数的对象,只有在运行时才知道。

我不明白对象的类型在编译时可能是未知的。从源代码上看是不是很明显?

【问题讨论】:

    标签: c++ compile-time dynamic-binding


    【解决方案1】:

    一点也不。考虑这个例子:

    struct A {
      virtual void f() = 0;
    };
    
    struct B : A {
      virtual void f() { std::cerr << "In B::f()\n"; }
    };
    
    struct C : A {
      virtual void f() { std::cerr << "In C::f()\n"; }
    };
    
    static void f(A &a)
    {
      a.f(); // How do we know which function to call at compile time?
    }
    
    int main(int,char**)
    {
      B b;
      C c;
      f(b);
      f(c);
    }
    

    当全局函数f被编译时,没有办法知道它应该调用哪个函数。事实上,它每次都需要调用不同的函数。第一次调用f(b)需要调用B::f(),第二次调用f(c)需要调用C::f()

    【讨论】:

      【解决方案2】:

      C++ 有一个指针 的概念,其中变量只保存一个实际对象的“句柄”。实际对象的类型在编译时是未知的,只有在运行时才知道。示例:

      #include <iostream>
      #include <memory>
      
      class Greeter {
      public:
          virtual void greet() = 0;
      };
      
      class HelloWorld : public Greeter {
      public:
          void greet() {std::cout << "Hello, world!\n";}
      };
      
      class GoodbyeWorld : public Greeter {
      public:
          void greet() {std::cout << "Goodbye, world!\n";}
      };
      
      int main() {
          std::unique_ptr<Greeter> greeter(new HelloWorld);
          greeter->greet();    // prints "Hello, world!"
          greeter.reset(new GoodbyeWorld);
          greeter->greet();    // prints "Goodbye, world!"
      }
      

      另请参阅:Vaughn Cato 的回答,它使用 references(这是另一种持有对象句柄的方式)。

      【讨论】:

        【解决方案3】:

        假设你有一个指向派生对象的基类指针

        Base *pBase = new Derived;
        
        // During compilation time, compiler looks for the method CallMe() in base class
        // if defined in class Base, compiler is happy, no error
        // But when you run it, the method call gets dynamically mapped to Derived::CallMe()
        
        // ** provided CallMe() is virtual method in Base and derived class overrides it.
        
        pBase->CallMe(); // the actual object type is known only during run-time.
        

        【讨论】:

        • 考虑到 OP 提出的问题,这可能比 OP 的水平高出 方式
        • 尽管如此,我的例子比你的简单得多,但仍然有效地传达了它:)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-08-08
        • 1970-01-01
        • 2022-01-20
        • 2010-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多