2

所以我到处搜索,似乎找不到这个特定问题的答案。我正在使用带有 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。我已经尝试过成员初始化方法,但是编译器没有意识到受保护的变量。那么由于我不知道的一些奇怪的原因,它在这个类中找不到构造函数。即使包含对受保护成员变量(非继承)的构造函数的“错误”调用,它也会建议构造函数的正确版本。

我仍然不知道如何做到这一点。任何帮助是极大的赞赏。

4

5 回答 5

3

声明变量后,您必须设置它,否则您将像调用函数一样调用它。

this->b = Bar(x+3);

首选方法是使用初始化列表来避免不必要的Bar. 但是,如果您这样做,则需要在构造函数之外设置 b 上面的示例是如何执行此操作的。

于 2012-03-29T15:36:41.217 回答
2

DerFoo的构造函数不能(也不能)初始化b,这是Foo工作。DerFoo的构造函数只负责初始化DerFoo的直接子对象,即db和 的Foo基类DerFooFoo的构造函数反过来负责初始化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);
于 2012-03-29T16:27:11.860 回答
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初始化它自己的成员,这将通过调用Foo[a] 中的构造函数来实现。

[3],[4],两个表达式都采用this->member(i). 在初始化期间,语法member(i)会很好,member使用 的值进行初始化i。在初始化之外,语法意味着调用operator()( int )传递i. 这些成员已经被初始化,但如果你想重置它们,你需要分配而不是初始化它们。

于 2012-03-29T16:33:58.410 回答
0

b在 Foo 类中。访问它(肯定)使用

Foo::b = Bar(x-3);
于 2012-03-29T15:44:29.697 回答
-1

您不必使用初始化列表,此时您肯定也应该使用初始化列表。

在构造对象时,在输入构造函数的代码之前,所有成员变量都已经构造好了。如果您不提供初始化程序,它们将被默认构造。

同样,在已经构造变量之后,您也不能再次构造变量。您的

this->b(x+3)

不是告诉编译器构造b它是告诉它调用一个b在你的对象上命名的函数。您的类中不存在这样的函数,因此出现错误。请注意,一旦将对象构造为变量,就无法再次调用该变量的构造函数(仅更改值)。

=在大多数语言中,可以使用 as 更改值。因此你可以这样做:

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

于 2012-03-29T15:49:55.077 回答