初始化基类成员的首选方法 (c++)
Posted
技术标签:
【中文标题】初始化基类成员的首选方法 (c++)【英文标题】:Preferred way to initialize base class members (c++) 【发布时间】:2018-05-14 07:47:52 【问题描述】:我有一个基类:
class Base
protected:
int m_a;
virtual void foo() = 0;
还有一个派生类
class Derived : public Base
public:
Derived(int a);
基类是抽象的,所以只能创建派生类。 如何更好地实现派生的Ctor?
Derived::Derived(int a) : Base(a)
Base::Base(int a) : m_a(a)
或者
Derived::Derived(int a) m_a = a;
Base::Base()
将成员从 Base 构造函数中删除更好,因为它不能单独创建,还是保留在 Base 构造函数中以便为他保留分配?
【问题讨论】:
你心目中的“更好”是什么样的?无论如何,第一个违反准则是使用protected
数据成员。将其设为private
,其余部分如下。
更多的是基于意见。我总是更喜欢遵循第一种方式,因为 1. 所有 Base
类逻辑都保留在 Base
类中; 2.如果m_a
是const
,这是唯一的方法
不要使用受保护的数据成员。 Stroustrup 说,在语言中使用它们是错误的。所有数据都应该是私有的。看到现在只有一种方式做事了吗?这甚至在我们开始谈论 const 和不可复制数据、移动语义以及所有那些奇怪而美妙的东西之前。
@n.m. - “所有数据都应该是私有的”是什么意思?如果我有一些需要使用受保护成员的派生方法 - 你会更喜欢这个成员的 getter 和 setter,而不是保护它吗? getter 和 setter 也会受到保护吗?
“你更喜欢 getter 和 setter” 不,我更喜欢 重新设计。一个类不应该根据它拥有的内容来定义,而应该根据它做什么来定义。当你重新设计时,getter 和 setter 可以作为权宜之计。他们当然应该受到保护。
【参考方案1】:
您的第一个解决方案 - 为基类提供显式构造函数 - 作为一般模式更可取:
它避免了从 Base 继承的其他类忘记初始化 m_a。相反,类的签名表明需要初始化。
如果多个类从基类继承,并且初始化更复杂(例如范围检查),则此代码和策略不会分布在多个派生类中
如果 m_a 是不可变的,则需要构造函数初始化
派生类可能有不止一个 CTor,还有更多可以忘记的地方
唯一的缺点:打字多一点——只要你不计算额外的“我今天有点懒,所以不要忘记在所有派生类构造函数中初始化 m_a”
如 cmets 中所述,“签名宣布要求”足以使 IMO 成为默认模式,“另一种方式要求使 m_a 受保护”也是如此。
【讨论】:
【参考方案2】:我更喜欢:
Derived::Derived(int a) : Base(a)
Base::Base(int a) : m_a(a)
通过这种方式,您可以使您的代码更加封装并且Base
成员关心它的初始化列表,在基类构造函数中可以有更多的初始化逻辑,这取决于m_a 而不是仅仅初始化m_a
。在这种情况下,你将初始值传递给你的基类构造函数,然后他的构造函数中的派生类已经初始化了基类的构造函数。
您应该尝试将初始化值传递给您的 Base
类,假设您有 5 个 Derived
类,并且您需要在所有派生的 ctor 中初始化基类。
【讨论】:
以上是关于初始化基类成员的首选方法 (c++)的主要内容,如果未能解决你的问题,请参考以下文章
C++中的派生类,可以不定义对象直接调用基类的成员和调用自己的成员函数嘛???