我的代码段如下:
#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
)。
由于我认为Base
和Derived
都需要访问此字段,因此我在get
中定义了Base
成员函数,因此Derived
可以继承它。
然后我尝试从不同的对象中获取成员字段。
结果显示,我b
中的原始Base
仍然是d.get()
而不是Derived
中的原始{{1}},这是我期望代码执行的操作。
代码(或我的理解)有什么问题吗?是否在规范中指定了此行为?覆盖成员字段并正确定义其getter和setter的正确方法是什么?
答案 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>
答案 3 :(得分:2)
你应该按如下方式重写你的Derived :: ctor:
Derived(double _b)
:Base(_b)
{}
并删除Derived类中的已归档b
。而是将b
类中的Base
标记为受保护。
修改强>
无视所有这一切
我在你的代码中发现了一个问题:
Base b = d;
您将派生对象复制到基础。它仅复制基本字段。如果你想要多态,请尝试下一步:
Base *b = &d;
b->get()