如果没有默认参数,C++ 派生类将无法工作,即使这样也是错误的

标签 c++ class

假设我有一个基类A,两个派生类BC,它们是virtual public A , 和一个最终类 D,它是 public 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 充当一个接口(interface)类,它具有 m_x 作为 BC 的公共(public)变量>,根据需要使用和修改,而 D 使用 A 的变量进一步计算所需的 m_w。这两个虚拟类是根据需要调用的,来自D

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

a) 原样(无默认参数),第一个错误行:
16:29 没有用于调用 A::A() 的匹配函数

b) 没有默认参数,将第 19 行更改为 A::A(m_z):
不能直接调用构造函数‘B::A’[-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++ 不会不允许第二次猜测,当 D 创建时,A 构造函数是否会从 BC 调用。


拍摄 2

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

Suppose I have temperature readings (A) from different countries (B, C, etc), and I have to filter/present/display them on screen/graph/somehow (D) (just an example).

所以你有不同的温度测量单位,你想用同一个测量单位一起显示它们。为了方便起见,我说目标单位是°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++ 派生类将无法工作,即使这样也是错误的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39016944/

相关文章:

jquery - 如何从元素中获取第二个类名?

java - JMock 期望中的第二组括号

c++ - 下面代码宏定义的含义

c++ - 这种线程间对象共享策略合理吗?

C++ 类型名称作为 static_assert 中错误报告的文字字符串

c++ - 如何使用匿名模板参数强制模板参数类从 super 派生

c++无法将父类指针作为类型定义对静态模板成员的引用

c++ - 初始化 vector 以包含 13 个元素

c# - 使用 Emailmessage 类检索邮件正文

Python - 类方法多进程安全吗?