[英]Inherited class initializing a custom made class using non-default constructor
因此,我到处搜索,似乎找不到这个特定问题的答案。 我正在使用带有cygwin和gcc 3.4.4 cygming special的winXP。
问题:我有一个类,用作与某些抽象方法和受保护变量的接口,这些抽象方法和受保护变量应该在从该类继承的每个类中。 现在,我还有另一个类,它是此接口的成员变量。
class Bar {
private:
int y;
public:
Bar(int why);
};
Bar::Bar(int why) : y(why) {}
class Foo {
protected:
Bar b;
public:
Foo(int x);
virtual void print_base();
};
Foo::Foo(int x) : b(x+3) // Have to use initializer list here.
{
//this->b(x+3); // doesn't work
}
class DerFoo : public Foo {
protected:
Bar db;
public:
DerFoo(int x);
};
DerFoo::DerFoo(int x) : Foo(x),
db(x+3) // (Bar)(int) being called, works fine
// db(4.0, 30) // no matching function for call to Bar::Bar(double, int)
// note: candidates are Bar::Bar(const Bar&), Bar::Bar(int)
// b(x-3) // doesn't work class DerFoo does not have any field named 'b'
{
//this->b(x - 3); // Doesn't work, error no match for call to (Bar)(int)
//this->db(x + 3); // Doesn't work, error no match for call to (Bar)(int)
}
因此,您可以看到的问题在于派生的foo类内部,DerFoo如何初始化b。 我尝试了成员初始化方法,但是编译器没有意识到受保护的变量。 因此,由于某种我不知道的奇怪原因,它无法在此类中找到构造函数。 即使要对受保护的成员变量的构造函数(不继承)进行“错误”调用,它也会建议构造函数的正确版本。
我仍然不知道该怎么做。 任何帮助是极大的赞赏。
声明变量后,必须对其进行设置,否则将像函数一样调用它。
this->b = Bar(x+3);
首选方法是使用初始化程序列表,以避免不必要的Bar
副本。 但是,如果需要这样做,则需要在构造函数之外设置b,上面的示例就是这样做的方法。
DerFoo
的构造函数不得(也不能)初始化b
,这是Foo
工作。 DerFoo
的构造仅负责初始化DerFoo
的直接子对象,即db
和Foo
其是基类的DerFoo
。 Foo
的构造函数负责初始化b
。
事件的顺序如下:
DerFoo
的构造函数调用Foo
的构造函数 Foo
的构造函数调用b
的构造函数 Foo
的构造函数运行其主体,使Foo
对象完全构建 DerFoo
的构造函数调用db
的构造函数 DerFoo
的构造函数运行其主体,使DerFoo
对象完全构建。 如果在DerFoo
构造函数中,您不喜欢Foo
构造函数留在b
的值,则可以使用以下任何一种语法为b
分配一个新值:
b = Bar(47);
this->b = Bar(47);
this->Foo::b = Bar(47);
Foo::b = Bar(47);
我觉得这个问题不是很清楚,但是让我们看看我是否了解您正在尝试做什么以及如何做。
DerFoo::DerFoo(int x) : Foo(x), [a]
db(x+3)
// db(4.0,30) [1]
// note: candidates are Bar::Bar(const Bar&), Bar::Bar(int)
// b(x-3) [2]
{
//this->b(x - 3); [3]
//this->db(x + 3); [4]
}
第一个错误是[1],在编译器告诉您没有Bar
构造函数同时使用double和int的情况。 该错误还列出了可以使用的两个可能的构造函数: Bar(int)
, Bar(Bar const &)
。 我不确定您打算如何使用此行,但您已经弄清楚(上一行)仅通过提供int
调用即可正常工作。
[2] b
不是DerFoo
的成员,因此无法在DerFoo
的初始化列表中初始化。 Foo
负责初始化自己的成员,这将通过在[a]中调用Foo
构造函数来实现。
[3],[4],两个表达式都采用this->member(i)
的形式。 在初始化期间,语法member(i)
会很好,使用i
的值初始化member
。 在初始化之外,语法意味着调用operator()( int )
传递i
的值。 这些成员已经被初始化,但是如果您想重置它们,则需要分配而不是初始化它们。
b
在Foo类内。 访问(肯定)使用
Foo::b = Bar(x-3);
您没有使用一个初始化列表,你肯定也应该在这一点上使用初始化列表。
在构造对象时,在输入构造函数的代码之前,已经构造了所有成员变量。 如果您不提供初始化程序,则将使用默认构造方法。
同样,在已经构造变量之后,您将无法再次构造它。 你的
this->b(x+3)
不是告诉编译器构造b
,而是告诉它在对象上调用名为b
的函数。 这样的函数在您的班级中不存在,因此会出现错误。 请注意,一旦将对象构造为变量,便无法再次调用该变量的构造函数(仅更改值)。
与大多数语言一样,可以使用=
更改值。 因此,您可以执行以下操作:
Foo::Foo(int x)
{
this->b = Bar(x+3);
}
这意味着您正在创建另一个无名的Bar
对象,并将其值分配给this->b
。 您应该知道,这意味着在创建Foo
时将创建两个Bar
对象。 首先,默认构造一个。 输入构造函数代码,然后输入新的无名代码。 然后,您最终将值分配给已构造的对象,因此此代码比使用初始化列表的代码效率低得多。
编辑 :
由于我错过了第二个在上面的代码中doesn't work
的某些附加信息,因此:
您还尝试直接在派生的DerFoo
对象的构造函数中初始化b
。 但是,一旦到达这部分代码,就已经构造好了。 因此,任何在派生构造函数中构造它的尝试都来得很晚。
因此,您必须向Foo
添加另一个构造函数,该构造函数接受该值并在DerFoo
的构造函数中使用该值。 此解决方案是可取的,因为它只会在b
构造一次Bar
对象。 如果无法添加此类构造函数,则需要在DerFoo
的构造函数代码中使用分配。
即使使用了作用域运算符,尝试直接在DerFoo
构造函数中初始化b
也不起作用。
DerFoo::DerFoo() : Foo::b(x-3) {}
仍会产生错误: http : //ideone.com/6H8ZD
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.