所以我搜遍了所有地方,似乎无法找到这个具体问题的答案。我正在使用winXP与cygwin和gcc 3.4.4 cygming special。
问题: 我有一个类作为一个接口与一些抽象方法和受保护的变量,应该在从这个类继承的每个类中。现在我还有另一个类,它是该接口的成员变量。
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。我已经尝试过成员初始化方法,但后来编译器没有实现有关受保护的变量。所以,由于一些奇怪的原因我不知道,它无法在这个类中找到构造函数。即使if包含对受保护成员变量(非继承)的构造函数的“错误”调用,它也会建议正确版本的构造函数。
我还不知道如何做到这一点。非常感谢任何帮助。
答案 0 :(得分:3)
声明变量后,你必须设置它,否则你将像函数一样调用它。
this->b = Bar(x+3);
首选方法是使用初始化列表来避免不必要的Bar
副本。但是,如果这样做,则需要在构造函数外部设置b,上面的示例是如何执行此操作。
答案 1 :(得分:2)
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);
答案 2 :(得分:1)
我发现这个问题不是很清楚,但让我们看看我是否明白你要做什么以及如何做。
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)
将很好,使用member
的值初始化i
。在初始化之外,语法意味着调用operator()( int )
传递i
的值。这些成员已经初始化,但是如果要重置它们,则需要分配而不是初始化它们。
答案 3 :(得分:0)
b
在Foo类中。访问它(肯定)使用
Foo::b = Bar(x-3);
答案 4 :(得分:-1)
您没有拥有来使用初始值设定项列表,此时您肯定应该使用初始值设定项列表。
在构造对象时,在输入构造函数的代码之前,已经构造了所有成员变量。如果您不提供初始化程序,它们将是默认构造的。
此外,在构建变量之后,您无法再次构造变量。您的
this->b(x+3)
没有告诉编译构造b
它告诉它在你的对象上调用一个名为b
的函数。这样的函数在你的类中不存在,因此就是错误。请注意,一旦将对象构造为变量,就无法再次为该变量调用构造函数(仅更改值)。
与大多数语言一样,可以使用=
更改值。因此你可以这样做:
Foo::Foo(int x)
{
this->b = Bar(x+3);
}
这意味着您正在创建另一个无名Bar
对象,并将其值分配给this->b
。您应该知道,这意味着,在创建Bar
时,您将创建两个Foo
个对象。首先是默认构造的,之前。输入构造函数代码,然后输入新的无名构造代码。然后,您将最终将值分配给已构造的对象,因此此代码比使用初始化列表的代码效率低得多。
编辑:
由于我错过了上面代码中的第二个doesn't work
,因此还有一些其他信息:
您还尝试直接在派生的b
对象的构造函数中初始化DerFoo
。但是,一旦达到这部分代码,它就已经构建完成了。因此,任何在派生构造函数中构造它的尝试都会迟到。
因此,您必须向Foo
添加另一个构造函数,该构造函数接受该值并在DerFoo
的构造函数中使用该值。此解决方案是首选,因为它只会在Bar
中构造一次b
对象。如果你不能添加这样的构造函数,那么你需要在DerFoo
的构造函数代码中使用赋值。
即使使用了作用域运算符,尝试直接在b
构造函数中初始化DerFoo
也不起作用。
DerFoo::DerFoo() : Foo::b(x-3) {}
仍会产生错误:http://ideone.com/6H8ZD