覆盖派生类中的成员字段

时间:2013-10-10 08:31:43

标签: c++ c++11

我的代码段如下:

#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

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

结果显示,我b中的原始Base仍然是d.get()而不是Derived中的原始{{1}},这是我期望代码执行的操作。 代码(或我的理解)有什么问题吗?是否在规范中指定了此行为?覆盖成员字段并正确定义其getter和setter的正确方法是什么?

4 个答案:

答案 0 :(得分:11)

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

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

答案 1 :(得分:7)

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

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

你可以通过装饰getter来实现类似的东西,但getter返回类型将始终是相同的:

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;
};

答案 2 :(得分:2)

我不确定我是否理解正确,但是“覆盖”你的意思是“替换”,你会使用模板:

#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>

Live example

答案 3 :(得分:2)

你应该按如下方式重写你的Derived :: ctor:

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

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

修改
无视所有这一切 我在你的代码中发现了一个问题:

Base b = d;

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

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