假设我有一个基类A
,两个派生类B
和C
是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
充当接口类,它具有m_x
作为B
和C
的公共变量,可以根据需要使用和修改,而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
中,您需要调用A
,B
和C
的构造函数,因为C ++不允许进行第二次猜测,因此在以下情况下是从A
还是B
调用C
构造函数D
已创建。拿2
由于您实际上希望
D
有条件地构造B
或C
的实例,因此需要重新组织设计。假设我有来自不同国家的温度读数(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/