【问题标题】:Why the following C++ program prints '0' instead of '6'?为什么下面的 C++ 程序打印 '0' 而不是 '6'?
【发布时间】:2015-12-06 16:55:15
【问题描述】:

我有两个名为 FWindowFFramwWindow 的类。 FFramwWindow 类继承了 FWindowFWindow 类包含两个构造方法。

第一个是默认构造函数,第二个包含一个 int 类型的参数。

我从 FFramwWindow 类默认构造函数中调用第二个构造函数来初始化 FWindow 类的一个名为“value”的成员变量。

但我不知道为什么它不起作用 -

class FWindow {
public:
    int value;
    FWindow() 
    {
        this->value = 0;
    }
    FWindow(int val) 
    {
        this->value = val;
    }
};

class FFramwWindow : public FWindow
{
public:
    FFramwWindow()
    {
        FWindow::FWindow(6);

        printf("value %d\n", this->value);
    }
};

int main(int argc, _TCHAR* argv[])
{
    FFramwWindow obj;

    return 0;
}

上面的代码打印-value 0

我预计它会在哪里打印 - value 6

似乎它只调用了默认的基类构造函数,而不是我明确调用的第二个。

注意:我使用的是 Visual Studio 2008

【问题讨论】:

  • 为什么要投反对票?我认为 C++ 将允许我在派生类构造函数体内显式调用基类构造函数。我想我可以用这种方式调用类构造函数 - 'FWindow::FWindow()' 就像我们调用基类析构函数一样。例如 - 'FWindow::~FWindow()'。如果 'FWindow::FWindow()' 创建一个本地对象,那么 'FWindow::~FWindow()' 会创建一个本地对象吗?

标签: c++ oop constructor


【解决方案1】:

因为你应该在构造函数中执行以下操作:

FFramwWindow() : FWindow(6)
{
....

在您的原始代码中,您创建一个 FWindow 的本地(在构造函数范围内)对象。

【讨论】:

  • 哦,对了,我还在试图弄清楚他对基础构造函数的调用是否在体内有效......
  • @alex 构造函数调用创建FWindow的本地对象?奇怪的。我认为在这种情况下 C++ 会更聪明。
  • @MohammadShuvo,编译器按你说的做。
  • @MohammadShuvo 它比这更聪明。成员变量和基类需要先初始化,然后才能在方法体中使用它们。该对象必须在使用前准备好使用。成员初始化器列表解决了这个问题。
  • @MohammadShuvo:你的意思是不太灵活,不允许你声明临时对象!
【解决方案2】:

代码

FWindow::FWindow(6);

不是调用父构造函数,而是创建FWindow的本地实例。在 C++ 中指定应该调用哪个 FWindow 构造函数的正确语法是

FFramwWindow() : FWindow(6)
{
    ...
}

如果不指定基类(和数据成员)使用的构造函数,C++ 使用默认构造函数,即

FFramwWindow()
{
    ...
}

等价于

FFramwWindow() : FWindow()
{
    ...
}

请注意,如果您有多重继承,您应该为每个基类使用构造函数,用逗号分隔它们。作为奖励信息,基本构造函数是按照继承定义中指定的顺序调用的,而不是您在构造函数中指定的顺序:

class A {
    A();
    A(int n);
    A(string s);
};

class B {
    B(int n = 6);
}

class C {
    C();
    C(float x);
}

class D: public A, public B, public C {
    D();
}

D::D() : C(3),A(5)
{
}

在本例中,创建D 的实例将依次调用A(5)B(6)C(3.0)D() 的构造函数

【讨论】:

  • 一般来说,它并不完全等价。 FFramwWindow(): FWindow() 指定FWindow 将被值初始化。如果没有这个,如果FFramwWindow 正在被默认初始化,它将是默认初始化。在这种特定情况下,它没有实际意义,因为 FWindow 有一个用户编写的构造函数。
【解决方案3】:

在声明派生类的构造函数时,必须调用基类的构造函数。考虑这个例子:

#include<iostream>
class base
{
public:
    int i;
    base()
    {
        i = 0;
    }
    base(int p)
    {
        i = p;
    }
};

class derived1: public base
{
public:
    derived1():base()
    {
        std::cout<<i<<std::endl; //i is 0 here
    }
};

class derived2: public base
{
public:
    derived2():base(10)
    {
        std::cout<<i<<std::endl; //i is 10 here
    }
};

class derived3: public base
{
public:
    derived3(int x):base(x)
    {
        std::cout<<i<<std::endl;
        //this takes an argument from the derived class's constructor
        //as base class's constructor's parameter
    }
};

int main()
{
    derived1 d1;
    derived2 d2;
    derived3 d3(9);
    return 0;
}

derived1 类中,调用base 类的第一个构造函数。在derived2 类中,调用了第二个构造函数。在第三种情况下,构造函数接受一个参数,该参数传递给基类的构造函数(这意味着我们使用的是基类的第二个构造函数)。

在您的代码中,您没有调用基类的构造函数,该构造函数默认调用不带参数的构造函数。这就是它输出 0 的原因。

FWindow::FWindow(6);

这个语句只是创建了一个 FWindow 类的临时新对象,它在这个语句执行后立即被销毁。构造函数意味着在创建对象时自动调用。它们不应该被手动调用。

你可以在这里找到一些解释:http://www.geeksforgeeks.org/possible-call-constructor-destructor-explicitly/

【讨论】:

  • 几乎是一个很好的答案。我建议进行编辑,以包括如何执行您在第一句话中的建议。
猜你喜欢
  • 2017-08-29
  • 2019-09-16
  • 1970-01-01
  • 1970-01-01
  • 2019-12-07
  • 1970-01-01
  • 1970-01-01
  • 2012-09-12
  • 1970-01-01
相关资源
最近更新 更多