重写派生类中的成员字段

Override member field in derived classes

本文关键字:成员 字段 派生 重写      更新时间:2023-10-16

我在下面有一个代码片段:

#include <iostream>
using namespace std;
class Base {
public:
    Base() : b(0) {}
    int get();
    virtual void sayhello() { cout << "Hello from Base with b: " << b << endl; }
private:
    int b;
};
int Base::get() {sayhello(); return b;} 
class Derived : public Base {
public:
    Derived(double b_):b(b_){}
    void sayhello() { cout << "Hello from Derived with b: " << b << endl; }
private:
    double b;
};
int main() {
    Derived d(10.0);
    Base b = d;
    cout << "Derived b: " << d.get() << endl;
    cout << "Base b: " << b.get() << endl;
}

运行编译的可执行文件,我发现结果超出了我在llvm-g++ 4.2机器上的预期。我的盒子上的输出是

Hello from Derived with b: 10
Derived b: 0
Hello from Base with b: 0
Base b: 0

我想在代码中做的是覆盖Derived类中的成员字段(b(。由于我认为BaseDerived都需要访问此字段,因此我在Base中定义了一个get成员函数,因此Derived可以继承它。然后我尝试从不同的对象获取成员字段。

结果表明,我仍然通过d.get()获得Base的原始b,而不是Derived中的原始,这就是我期望代码做的事情。代码(或我的理解(有什么问题吗?规范中是否指定了此行为?覆盖成员字段并正确定义其 getter 和 setter 的正确方法是什么?

生类中添加的新b不会覆盖 base 的b。它只是隐藏它。

因此,在派生类中,您有两个b并且虚拟方法打印相应的b

不能简单地重写成员字段,并且在编译Base::get时,b变量解析为Base::b,因此此方法将始终使用此值,而不是派生类中具有相同名称的另一个字段中的值。

覆盖

属性的常用方法是覆盖访问它的方式,即覆盖访问器(getter 和 setter(。

您可以通过装饰吸气剂来实现类似的东西,但吸气剂返回类型将始终相同:

class Base {
public:
    Base() : b(0) {}
    int get();
    virtual void sayhello() { cout << "Hello from Base with b: " << b << endl; }
protected:
    virtual int getB() {return b;}
private:
    int b;
};
int Base::get() {sayhello(); return getB();} 
class Derived : public Base {
public:
    Derived(double b_):b(b_){}
    void sayhello() { cout << "Hello from Derived with b: " << b << endl; }
protected:
    int getB() override {return b;} // conversion from double to int
private:
    double b;
};

我不确定我是否正确理解了您,但是"覆盖"的意思是"替换",您将使用模板:

#include <iostream>
using namespace std;
template< typename T >
class Base {
public:
    Base() : b(0) {}
    Base(T b_) : b(b_) {}
    T get();
    virtual void sayhello() { cout << "Hello from Base with b: " << b << endl; }
protected:
    T b;
};
template< typename T >
T Base<T>::get() {sayhello(); return b;} 
class Derived : public Base<double> {
public:
    Derived(double b_):Base(b_){}
    void sayhello() { cout << "Hello from Derived with b: " << this->b << endl; }
};
int main() {
    Derived d(10.0);
    Base<double>* b = &d;
    cout << "Derived b: " << d.get() << endl;
    cout << "Base b: " << b->get() << endl;
}

您在main中编码也尝试Base b = d;会导致切片,上述修复并确保您不会意外使用Base<int>而不是Base<double>

现场示例

你应该重写你的 Derived::ctor,如下所示:

Derived(double _b)
:Base(_b)
{}

并删除派生类中的归档b。而是将Base类中的b标记为受保护。

编辑
忽略所有这些我发现您的代码中有问题:

Base b = d;

您正在将派生对象复制到基。它仅复制基本字段。如果你想要多态性,请尝试下一步:

Base *b = &d;
b->get()