C++ 以基类为参数的派生类构造函数(这是一种好的做法吗?)
下面我有两个简单的类,一个是基类,另一个是从基类派生的类C++ 以基类为参数的派生类构造函数(这是一种好的做法吗?),c++,oop,constructor,C++,Oop,Constructor,下面我有两个简单的类,一个是基类,另一个是从基类派生的类 在派生类中有两个构造函数,一个接受基类和派生类所需的所有参数,另一个接受基类引用本身作为参数 我知道将基类引用作为参数的构造函数不是一个好的实践 然而,我想知道为什么这不是一个好的做法? 它实现了与其他构造函数相同的功能 有人能解释一下为什么这不是一个好的OOP实践吗 class Base { public: Base(int a, int b): m_a(a), m_b(b) {}
在派生类中有两个构造函数,一个接受基类和派生类所需的所有参数,另一个接受基类引用本身作为参数 我知道将基类引用作为参数的构造函数不是一个好的实践
然而,我想知道为什么这不是一个好的做法? 它实现了与其他构造函数相同的功能
有人能解释一下为什么这不是一个好的OOP实践吗
class Base
{
public:
Base(int a, int b):
m_a(a),
m_b(b)
{}
Base(const Base& b):
m_a(b.m_a),
m_b(b.m_b)
{}
~Base() {}
protected:
int m_a;
int m_b;
};
class Derived : public Base
{
public:
// Constructor which takes base class argument and initializes base
Derived(Base &base, int c):
Base(base),
m_c(c)
{}
Derived(int a, int b, int c):
Base(a, b),
m_c(c)
{}
~Derived() {}
private:
int m_c;
};
int main()
{
Base base(1,2);
Derived derived1(base, 3); //
Derived derived2(1,2, 3);
}
需要知道指定第一个派生构造函数的上下文 但是,使用
const Base
参数来定义它可能会更优雅。比如:
Derived(const Base &base, int c):
Base(base),
m_c(c)
{}
因此,它告诉编译器保护base
对象的状态
另外,如果您使用的是c++-11,那么您可能有兴趣声明:
using Base::Base;
在Derived
类中,是什么使得Derived
继承了Base
的构造函数。因此,您可以添加main()
:
这将完美地编译
在c++-11中,您还可以为m_c
数据成员设置默认值。比如说
int m_c = 0;
因此,从
Base
继承的构造函数将使派生的
保持一致状态我相信您展示的代码是不错的OOP实践。由于派生的
使用公共继承,因此派生的
用户知道并有权访问基
。因此,您没有添加任何依赖项,因此也没有使任何内容变得更具限制性或更复杂
这就是说,即使Derived
使用的是受保护继承或私有继承,根据Derived
的用户是否知道classBase
,这也不一定是不好的做法
想象一下:
class Derived { // no inheritance
public:
void doSomething(const X& b); // `X` could be `Base`, `Foo`, or `std::string` for that matter...
};
你能称之为上述不良行为吗?我想不是。这里的关键是,正如您所展示的代码(假设您将const限定符添加到Base&正如lrleon所建议的那样)使用
Base
作为值类型<代码>派生的没有保存对传入的基本对象的指针/引用,因此您使用的是正常的参数传递,关于参数传递没有任何异常或不好的做法。您从哪里发现这不是一个好的做法?我想这主要取决于您的设计。若Derived
是Base
的扩展或包装,那个么为什么不呢!但我想它可能会在实现中引起一些麻烦,主要是如果您使用指针,而不是每次都复制所有内容(只需要小心并了解Base
)的实现。我认为,如果您可以将派生的
视为独立于基础
的东西,或者您想隐藏实现,那么这种做法就不太好了。我理解您的意思,但这不是我想要的。几乎所有的C++教程或书籍都指定了派生的所有基础参数和初始化基本成员,我想知道为什么/不应该派生类作为参数。现在可以认为它不是有效的代码,因为额外的拷贝,但这是一个不同的问题。
class Derived { // no inheritance
public:
void doSomething(const X& b); // `X` could be `Base`, `Foo`, or `std::string` for that matter...
};