覆盖基类成员变量的初始值
Posted
技术标签:
【中文标题】覆盖基类成员变量的初始值【英文标题】:Override initial value of a member variable of base class 【发布时间】:2016-01-04 13:33:47 【问题描述】:我现在对继承很困惑。我计划简单地覆盖变量的初始值。在下面的代码中,我只是继承了基类并尝试获取它的名称,该名称与类一起保存为字符串。我希望派生类可以覆盖这个值,但它没有这样做。
我的预期输出是
Derived
Derived
但是我得到了
Base
Base
以下实现的正确方法是什么?
#include <iostream>
#include <string>
struct Base
virtual ~Base() = default;
virtual void id()
std::cout << id_ << std::endl;
std::string id_ = "Base";
;
struct Derived : public Base
virtual ~Derived() = default;
std::string id_ = "Derived";
;
int main()
Base* b = new Derived();
Derived* d = new Derived();
b->id();
d->id();
delete d;
delete b;
return 0;
【问题讨论】:
成员变量不能是虚拟的(即可覆盖),只能是方法。 【参考方案1】:以下实现的正确方法是什么?
听起来很难,这实际上取决于您想要实现的目标。
我猜测我们只是在询问一个对象它是什么类型,而不管我们调用的是哪个接口:
struct Base
virtual ~Base() = default;
virtual const std::string id() const
return "Base";
;
struct Derived : Base
virtual const std::string id() const override
return "Derived";
;
这是另一种方式:
struct Base
virtual Base(std::string ident = "Base")
: _id(std::move(ident))
virtual ~Base() = default;
std::string& id() const
return _id;
private:
std::string _id;
;
struct Derived : Base
Derived() : Base("Derived")
;
另一个,使用值是接口,但注意这将禁用赋值运算符
struct Base
virtual Base(std::string ident = "Base")
: id(std::move(ident))
virtual ~Base() = default;
const std::string id;
;
struct Derived : Base
Derived() : Base("Derived")
;
这个列表绝不是详尽的。
【讨论】:
但这是一个非常好的开始 :) 它为 OP 提供了几种实现这一目标的方法,我相信实验会证明哪一种最适合他们。【参考方案2】:存在虚拟函数,而不是虚拟成员变量。
您在Derived
类中所做的是定义 一个隐藏其父级的新成员变量id_
。但是,id()
函数指的是在该上下文中定义的id_
。
如果你想覆盖行为,你应该覆盖id()
函数:
class Derived: public Base
std::string id() const override return "Derived";
;
【讨论】:
没有其他更通用的方法吗? 我推荐了一个。这个或那个更好取决于你的情况,所以权衡一下。【参考方案3】:为什么不简单地给Base
一个构造函数来设置id
并让Derived
用它的“覆盖”值调用这个构造函数? Boom:根据派生类型的“虚拟数据”。
话虽如此,虚拟方法可能更类似于封装,并为以后更精细的行为提供机会。
(编辑:我将其作为评论发布,然后将其转换,此时理查德刚刚击败我发布答案。没有复制!)
【讨论】:
【参考方案4】:由于函数 id() 是虚函数,因此在这两种情况下对象指针都是派生类型。
Base* b = new Derived(); // object type is Derived
b->id();
这里 b 是 Derived 类型的指针 但是“派生”类没有 id() 的实现,因为派生类对象的虚拟查找表中没有 id() 条目,因此它将调用基类函数 id()
其他情况也类似
Derived* d = new Derived(); //object type is Derived
d->id();
由于派生类中没有定义 id() 方法,它只会调用基类 id()。
还有一个疑问是您如何在类中初始化变量“id_”?
【讨论】:
不,该指针非常类似于Base
类型,而不是 Derived
,尽管它可能在运行时通过 vtable 到达。您对初始化id_
有什么疑问(问题?)?这是大括号或等号初始化,其中成员变量可以被赋予默认值,而不会出现在构造函数初始化列表中。
你的意思是std::string id_ = "Base";在课堂上是正确的??是否可以在类中初始化数据成员(不是静态的)?我在 VS 2012 中尝试过,但它抛出错误“不允许数据成员初始化”
VS 经常落后于 C++ 标准的一些新特性,而且这个特性是在 C++11 之后不久出现的,其中添加了这个特性。是的,这是允许的。只是搜索它。 (顺便说一句,这使得类型非 POD)以上是关于覆盖基类成员变量的初始值的主要内容,如果未能解决你的问题,请参考以下文章