假设下面的示例,其中SecondClass从FirstClass继承,并且其构造函数应该与FirstClass的构造函数做同样的事情。我不想重复它,所以我这样做:
SecondClass(int x) : FirstClass(x) {...}
同时,我想填充name
成员,每个类应具有不同的值。在FirstClass中,我使用
FirstClass(int x) : BaseClass("first"), x(x) {...}
在SecondClass中,我尝试过
SecondClass(int x) : FirstClass(x), name("second")
(显然)无法编译,因为“类'SecondClass'没有任何名为'name'的字段” 。
那么,我该如何实现自己想要的?我不想在每个类构造函数中传递name
作为参数(这似乎是一种标准方法),因为它应该是固定的,而不是由调用方设置的。
完整的示例代码:
#include <iostream>
#include <string>
using namespace std;
class BaseClass {
protected:
string name;
public:
BaseClass(const string name) : name(name) {};
virtual void doSomething() {};
};
class FirstClass : public BaseClass {
protected:
int x;
public:
FirstClass(int x) : BaseClass("first"), x(x) {
cout << "FirstClass constructor, name=" << this->name << endl;
// do something more with `x`
};
virtual void doSomething() {
// do something with `x`
}
};
class SecondClass : public FirstClass {
public:
// SecondClass's constructor should do the same as FirstClass,
// but I want this->name to contain "second"
SecondClass(int x) : FirstClass(x), name("second")
{
cout << "SecondClass constructor, name=" << this->name << endl;
};
virtual void doSomething() {
// do something else with `x`
};
};
int main()
{
BaseClass *c1, *c2;
c1 = new FirstClass(1);
c2 = new SecondClass(1);
c1->doSomething();
c2->doSomething();
}
答案 0 :(得分:4)
您可以像重载任何旧函数一样重载构造函数,因此重载.see-all-categories
的构造函数可以采用字符串名称:
FirstClass
但是,任何人都可以用非FirstClass(int x, string name) : BaseClass(name), x(x) {
的名字来制作FirstClass
!要解决此问题,可以使此构造函数为"first"
,以便只有孩子可以调用它:
protected
然后您可以从protected:
FirstClass(int x, string name) : BaseClass(name), x(x) {
构造函数中调用它:
SecondClass
答案 1 :(得分:4)
如果您同时继承BaseClass
中的FirstClass
和SecondClass
,则虚拟继承将“解决”该问题。我不建议这样做,但是这样做时,在实例化SecondClass
时,FirstClass
不会重新初始化BaseClass
:
#include <iostream>
#include <memory>
#include <string>
using std::cout, std::string;
class BaseClass {
protected:
string name;
public:
BaseClass(const string Name) : name(Name) {
cout << "BaseClass, name=" << this->name << "\n";
};
virtual ~BaseClass() {} // <- you really DO need this
};
class FirstClass : public virtual BaseClass {
protected:
int x;
public:
FirstClass(int X) : BaseClass("first"), x(X) {
cout << "FirstClass, name=" << this->name << "\n";
};
};
class SecondClass : public virtual BaseClass, FirstClass {
public:
SecondClass(int X) : BaseClass("second"), FirstClass(X) {
cout << "SecondClass, name=" << this->name << "\n";
};
};
int main() {
// this is a better alternative than raw base class pointers:
std::unique_ptr<BaseClass> c1, c2;
cout << "--- FirstClass ---\n";
c1 = std::make_unique<FirstClass>(1);
cout << "--- SecondClass ---\n";
c2 = std::make_unique<SecondClass>(2);
cout << "---\n";
}
输出:
--- FirstClass ---
BaseClass, name=first
FirstClass, name=first
--- SecondClass ---
BaseClass, name=second
FirstClass, name=second
SecondClass, name=second
---
答案 2 :(得分:3)
解决问题的方法可能在于改变对各种班级职责的看法。
最好让非叶子类处于非实例状态。如果您遵循此准则,FirstClass
将无法实例化,因此构造函数也将被
FirstClass(int x) : BaseClass("first"), x(x) {...}
没有道理。仅
FirstClass(std::string name, int x) : BaseClass(name), x(x) {...}
很有道理。然后,SecondClass
恰如其分。
SecondClass(int x) : FirstClass("second", x) { ... }
如果应该以“名称”表示派生最多的对象类型,则最好使用virtual
成员函数而不是基类中的成员变量来返回它。
class BaseClass
{
...
virtual std::string getName() const = 0;
...
};
class FirstClass : public BaseClass
{
...
virtual std::string getName() const { return "first"; }
...
};
class SecondClass : public FirstClass
{
...
virtual std::string getName() const { return "second"; }
...
};