【问题标题】:Late binding for const attributes in C++ classes?C++ 类中 const 属性的后期绑定?
【发布时间】:2011-10-03 14:55:18
【问题描述】:

我知道类属性没有后期绑定。但我需要一个好的模式来做到这一点:

#include <cstdlib>
#include <iostream>
using namespace std;

class B
{
public:
    const int i;
    B() : i(1) {}
};

class D : public B
{
public:
    const int i;
    D() : i(2) {}
};


int main()
{
    D d;
    B *ptr = &d;

    cout << ptr->i << endl;

    return 0;
}

输出是1,但我期望2。我想,我应该使用不同的模式。有什么建议吗?

【问题讨论】:

  • 你需要在运行时做一些事情,比如地图

标签: c++ oop class


【解决方案1】:

获得输出的i 的版本取决于compile-time 类型定义。你已经定义了两个不同的变量,所以你会得到两个不同的结果。解决这个问题的方法是确保变量只有一个版本。您可以在 B 中使用构造函数来初始化 const 变量。

class B
{
public:
    const int i;
    B() : i(1) {}
protected:
    B(int j) : i(j) {}
};

class D : public B
{
public:
    D() : B(2) {}
};

【讨论】:

    【解决方案2】:

    您需要使用虚拟方法,就像 C++ 中的所有后期绑定一样。

    class B
    {
    public:
        virtual int get_i() const { return 1; }
    };
    
    class D : public B
    {
    public:
        virtual int get_i() const { return 2; }
    };
    

    【讨论】:

    • 我经常使用这种模式,但是没有虚函数有没有更好的模式?
    • @MasoudM.:不,这是 模式。你为什么害怕它?
    • 你知道,当我阅读问题时,我认为你的想法也是正确的,然后我阅读了接受的答案并打了自己的头(比喻地说)并说“Doh!”。
    • @Omnifarious:虽然接受的答案解决了手头的确切问题,但它不处理问题的标题,也就是说,它不会产生后期绑定,而是产生一种解决方法值与派生最多的对象的类型无关的情况(一般意义上,即总是会访问B::i
    • @DavidRodríguez-dribeas:这是真的,但对于常量类成员,公认的答案是比后期绑定更好的解决方案。构造类后该值不会改变。不需要后期绑定。人们通常不会问正确的问题。
    【解决方案3】:

    您混淆了数据成员 B::i(初始化为 1)和 D::i(初始化为 2)。它们不一样,通过B * 调用会得到B::i,而不是D::i

    为了获得多态行为,您需要使用virtual 函数。 (另一种方法在 Mark Ransom 的回答中。)

    【讨论】:

      【解决方案4】:

      您只是向派生类添加新成员,这也恰好隐藏基类的成员。那不是你想要的。而是使用虚函数:

      class B
      {
        int m_i;
      public:
        virtual ~B() { }
        virtual int get() const { return m_i; }
      };
      
      class D : public B
      {
        int m_j;
      public:
        virtual int get() const { return m_j; }
      };
      

      用法:

      D d;
      B & b = d;
      std::cout << b.get() << std::endl;  // correct dynamic dispatch
      

      【讨论】:

        【解决方案5】:

        虚拟分派适用于函数成员,但不适用于数据成员。

        如果您迫切需要两个类中的同名变量,那么您可以使用访问器函数来完成这项工作:

        #include <cstdlib>
        #include <iostream>
        using namespace std;
        
        class B
        {
            const int i;
        public:
            B() : i(1) {}
            virtual int getI() { return i; }
        };
        
        class D : public B
        {
            const int i;
        public:
            D() : i(2) {}
            virtual int getI() { return i; }
        };
        
        
        int main()
        {
            D d;
            B* ptr = &d;
        
            cout << ptr->getI() << endl;
        }
        
        // Output: 2
        

        Live demo.

        【讨论】:

        • 但它需要在所有子类中重复virtual int getI() { return i; }
        • @MasoudM.:正确。而且,实际上,这是一件的事情。当其中一个派生类的行为发生轻微变化时,您可以随时实现它。
        猜你喜欢
        • 2011-02-17
        • 1970-01-01
        • 1970-01-01
        • 2023-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多