繁体   English   中英

继承的类使用非默认构造函数初始化自定义类

[英]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的直接子对象,即dbFoo其是基类的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM