【问题标题】:Base class to derive class access - How?派生类访问的基类 - 如何?
【发布时间】:2012-01-18 08:06:38
【问题描述】:

如何通过基类对象访问派生类的功能? 我已经编译并运行了程序,没有任何错误(vs2010 express edition)。 任何人都可以澄清这个话题吗?

#include <iostream>
using namespace std;
class A {
public:
    void f1() { cout << " f1 \n"; }
};

class B : public A{
    int x;
public:
    void f2(int x) {this->x = x; cout << "f2 " << this->x <<"\n";}
};

int main(int argc, char * argv[])
{
    A * aaa = new A();    // created a base instance
    B * b = (B *) aaa;    // typecasted it to derived class
    b->f2(5);   // try to access function, which should not be possible (run-time error?)
    return 0;
}

--> 输出

f2 5   // which concept is supports this output?

【问题讨论】:

    标签: c++


    【解决方案1】:

    这是不可能的,因为没有这样的方法。您刚刚调用了 undefined 行为,而您的编译器正在欺骗您。

    让我们玩游戏来见证这一点in action

    #include <iostream>
    
    struct A {
      A(int i = 0): value(i) {}
    
      int value;
    };
    
    struct B: A {
      B(int i): A(0), other(i) {}
    
      void set(int i) { other = i; }
    
      int other;
    };
    
    int main(int argc, char* argv[]) {
      A* a = new A[2];
      B* b = (B*)a;
      b->set(argc);
    
      std::cout << a->value << " " << (a+1)->value << "\n";
      std::cout << b->value << " " << b->other << "\n";
    }
    

    输出:

    0 1
    0 1
    

    哦!数组中的第二个A怎么改了?

    你对编译器撒了谎,它对你撒了谎……程序写到了它不应该写的地方。

    【讨论】:

      【解决方案2】:

      您所做的是 C 风格的 upcast,这会导致 undefined 对象内容 - 认为不建议将其与 C++ 一起使用,因为我们有更好的工具在那里可用。请查看 static_cast 和 dynamic_cast - 他们将确保您的演员表能够正常工作。例如,如果你会这样做

      B * b = dynamic_cast<B*>(aaa);
      

      你甚至无法编译它,因为 A 不是多态的,即使它是多态的并且类不匹配,它也会返回 NULL 而不是“未定义的东西”。

      请注意,动态转换比 static_cast 或 C 样式转换(其行为或多或少类似于 static_cast)要贵一些 - 但由于它们已定义的行为,您可能会考虑至少在调试版本中使用这些:

      #ifdef _DEBUG
          assert(dynamic_cast<B*>(aaa));
      #endif
      

      这可以防止由于未定义的行为(我假设您使用调试版本进行测试)导致的 a) 向上转换和 b) 运行时错误。

      【讨论】:

      • 谢谢 Coder02,我知道 C++ 有各种各样的强制转换关键字,但我从没想过我正在执行 C-Style Typecasting。谢谢大家的回复。这是一个很大的帮助:)
      • 别搞错了——C 风格的强制转换并不总是坏事,也并不总是在 C++ 中导致未定义的结果——这只是你的情况,因为 A 不是从 B 继承的。@Anders已经回答了这在内存中的样子以及为什么在这种情况下结果未定义。
      【解决方案3】:

      这是未定义的行为(即它是偶然发生的)。

      【讨论】:

        【解决方案4】:

        考虑一下:

        struct A
        {
           int i;
           short s;
        };
        
        struct B : A
        {
           long p;
        };
        
        struct A a;
        
        +-----+-----+
        |  i  |  s  |
        +-----+-----+
        
        struct B* b = (B*)&a;
        

        现在访问结构成员 p; (b-&gt;p)

        您认为 p 具有有效值是否合理?它仍然指向“a”实例。

        你应该看看 dynamic_cast 和虚函数

        【讨论】:

          【解决方案5】:

          编译实际上将 b->f2 视为 f2(b) 和 f2(b) 等于(伪代码)

          address_of_x = b+offset_x_in_B
          int x;
          memcpy(&x, address_of_x, sizeof(int));
          std::cout<<x<<std::endl;
          

          其中 offset_x_in_B 是编译器确定的 c++ 对象模型的值。

          所以当 b 是 A 实例时,行为将是未定义的(如果 A 只有一个 int 成员,而不是 x,则应该显示它。)

          【讨论】:

            猜你喜欢
            • 2017-09-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-05-23
            • 1970-01-01
            • 2011-07-14
            • 1970-01-01
            相关资源
            最近更新 更多