假设我有一个基类A,两个派生类BCvirtual public A,最后一个类Dpublic B, public C。我试图为此编写一个工作代码:

#include <iostream>

class A
{
protected:
    int m_x;
public:
    A(int a): m_x {2 * a} { std::cout << "A()" << '\n'; }
};

class B : virtual public A
{
private:
    int m_y, m_z;
public:
    B(int a): m_y {a * a}
    {
        m_z = 2 * m_y + 1;
        A(m_z);
        std::cout << "B()" << '\n';
    }
    int getVal() { return m_y; }
};

class C : virtual public A
{
private:
    int m_p, m_q;
public:
    C(int a): m_p {1 - a}
    {
        m_q = m_p - 3 * a;
        A(m_q);
        std::cout << "C()" << '\n';
    }
    int getVal() { return m_p; }
};

class D : public B, public C
{
private:
    int m_w;
public:
    D(int a, int b)
    {
        switch (b)
        {
        case 1: { B(a); break; }
        case 2: { C(a); break; }
        }
        m_w = m_x * a;
        std::cout << "D()" << '\n';
    }

    int getVal() { return m_z; }
};

int main(int argc, char *argv[])
{
    D d {5, 1};
    std::cout << d.getVal() << '\n';

    return 0;
}


所有类通常都有自己的.h.cpp文件,我对其进行了压缩,其公式纯属虚构。简而言之,A充当接口类,它具有m_x作为BC的公共变量,可以根据需要使用和修改,而D使用A变量以进一步计算所需的m_w。从D根据需要调用这两个虚拟类。

我的问题:如果没有给出默认参数,我将无法编译上面的代码,但是如果给出默认参数,则结果是错误的。

a)照原样(无默认参数),第一个错误行:
16:29 no matching function for call to A::A()

b)没有默认参数,将第19行更改为A::A(m_z)
cannot call constructor ‘B::A’ directly [-fpermissive]
(我认为这很有意义,没有B::A这样的东西)

c)使用默认参数:A = 2,B = 3,C = 4,输出:

A()
A()
B()
A()
C()
A()
A()
B()
D()
10


看起来很糟糕(我不知道为什么要打这么多电话),但也应该是:
B(5) =>
m_y = 5 * 5 = 25
m_z = 2 * 25 + 1 = 51
A(51) =>
m_x = 2 * 51 = 102
最后:
m_w = 102 * 5 = 510

...不是吗?有人可以告诉我我在做什么错吗?

最佳答案

您需要在初始化列表中而不是在构造函数主体中调用基类构造函数。

更换

B(int a): m_y {a * a}
{
    m_z = 2 * m_y + 1;
    A(m_z);
    std::cout << "B()" << '\n';
}


通过

B(int a): A(2 * a * a + 1), m_y {a * a}
{
    m_z = 2 * m_y + 1;
    std::cout << "B()" << '\n';
}


等等。

在类D中,您需要调用ABC的构造函数,因为C ++不允许进行第二次猜测,因此在以下情况下是从A还是B调用C构造函数D已创建。



拿2

由于您实际上希望D有条件地构造BC的实例,因此需要重新组织设计。


  假设我有来自不同国家的温度读数(A)(B,
  C等),我必须对其进行过滤/显示/显示
  屏幕/图形/以某种方式(D)(仅作为示例)。


因此,您有不同的温度测量单位,并且希望将它们一起显示在同一测量单位中。为了方便我,我说目标单位是°C。

让我们设计温度等级以及一些帮助程序和工厂方法

int CelsiusToFahrenheit(int c)
{ return /* somehow calculate F from c */; }

int FahrenheitToCelsius(int f)
{ return /* somehow calculate °C from f */; }


class Temperature
{
protected:
    int m_temperatureCelsius;
public:
    Temperature(int temperatureCelsius): m_temperatureCelsius { temperatureCelsius }
    { std::cout << "A()" << '\n'; }

    int GetCelsius()
    { return m_temperatureCelsius; }

    int GetFahrenheit()
    { return CelsiusToFahrenheit(m_temperatureCelsius); }
};

Temperature* CreateTemperatureFromCelsius(int c)
{ return new Temperature(c); }

Temperature* CreateTemperatureFromFahrenheit(int f)
{ return new Temperature(FahrenheitToCelsius(f)); }


现在,如果您有不同的国家/地区,并且想要为每个国家/地区项目注册温度,则可以按以下方式定义国家/地区(请注意:还有许多其他方式)

class BaseCountry
{
    protected:
        Temperature* m_temperature;
    public:
        BaseCountry()
        { }

        virtual ~BaseCountry() = 0; // abstract class

        int GetCountryTemperatureCelsius()
        { return m_temperature ? m_temperature->GetCelsius() : 0; }
}

class CountryA : public BaseCountry
{
    public:
        CountryA(int temperatureC)
        { m_temperature = CreateTemperatureFromCelsius(temperatureC); }

        ~CountryA()
        { delete m_temperature; }
}


class CountryB : public BaseCountry
{
    public:
        CountryB(int temperatureF)
        { m_temperature = CreateTemperatureFromFahrenheit(temperatureF); }

        ~CountryB()
        { delete m_temperature; }
}


int main(int argc, char *argv[])
{
    BaseCountry& c1 = CountryA(10);
    BaseCountry& c2 = CountryB(10);

    // display 10
    std::cout << c1.GetCountryTemperatureCelsius() << '\n';
    // display the number in °C for 10 F
    std::cout << c2.GetCountryTemperatureCelsius() << '\n';

    return 0;
}


在显示/屏幕/图表类中,您可以保存一个CountryBase引用数组,并访问它们的标准化温度,以°C为单位,而无论它们是如何构建的。

关于c++ - 如果没有默认参数,C++派生类将无法正常工作,甚至会出错,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39016944/

10-10 20:44