我们正在尝试在项目中限制primitive types
,在该项目中,我们可以检查派生类的实例的数据值是否在有效范围内(min
和max
成员变量,受保护以class
为基础的class
)。
我的问题是,有没有一种方法可以静态地初始化派生类的min
和max
变量,而不是每次实例化派生的{ {1}}。
在class
中,这将在静态初始化块中,但是我不确定如何在class
中进行此操作。
我知道我可以在派生的C#
中初始化它们,但是每次这样做似乎很浪费。
我想我正在寻找在基类中声明但随后在派生类中静态定义的抽象数据成员。
C++
答案 0 :(得分:2)
不,你不能。
此外,如果您想为不同的派生类使用不同的Min / Max值,则基类中的静态成员将永远无法工作。 (如果没有,则可以在基址中静态初始化)。 每个派生类将共享Min和Max的相同实例。 因此,一旦您在派生类中更改/初始化(非静态)值,它们将针对基类和其他派生类进行更改。参见this link。
我认为您需要最小,最大虚拟功能。像这样:
class BoundedFloat{
public:
BoundedFloat(const float v) : Value(v) {}
virtual float Min() { return -10; }
virtual float Max() { return 10; }
protected:
float Value;
}
class Temperature : public BoundedFloat
{
public:
Temperature(const float v) : BoundedFloat(v) {}
virtual float Min() override { return -40; }
virtual float Max() override { return 80; }
}
答案 1 :(得分:2)
除了一些重新设计之外,我认为没有任何方法可以精确地完成您想要的事情。请记住,对于未标记为static
的成员,类类型的每个对象都有自己的那些成员副本。如果您有多个Temperature
类型的对象,则每个对象都有自己的Min
和Max
,因此所有这些对象都需要在某个时刻初始化。此外,除非您以某种方式让它知道,基类BoundedFloat
不能知道它正在使用的几个可能的派生类中的哪一个,而仅传入min和max值可能是“删除它的最简单方法”。知道”。
但是与此相关的“浪费”(编码和维护工作?CPU运行时间?成员变量使用的内存?)对我来说似乎并不那么大。
仍然,您可能需要考虑一些重新设计的选项:
将数据从成员更改为虚拟getter函数。
class BoundedFloat
{
public:
BoundedFloat(const float v) : Value(v) {}
virtual ~BoundedFloat() = default;
protected:
BoundedFloat(const BoundedFloat&) = default;
BoundedFloat(BoundedFloat&&) = default;
BoundedFloat& operator=(const BoundedFloat&) = default;
BoundedFloat& operator=(BoundedFloat&&) = default;
float Min() const = 0;
float Max() const = 0;
float Value;
};
class Temperature : public BoundedFloat
{
public:
Temperature(const float v) : BoundedFloat(v) {}
float Min() const override { return -40.0f; }
float Max() const override { return 80.0f; }
};
现在,每个派生类均对其最小/最大值负责。尽管这种方法有其自身的成本,但对您而言可能不重要。
Flyweight模式
class BoundedFloat
{
protected:
struct Data {
float Min;
float Max;
};
BoundedFloat(const float v, const Data& data_in)
: Value(v), data(data_in) {}
protected:
BoundedFloat(const BoundedFloat&) = default;
BoundedFloat(BoundedFloat&&) = default;
BoundedFloat& operator=(const BoundedFloat&) = default;
BoundedFloat& operator=(BoundedFloat&&) = default;
float Value;
const Data& data;
};
class Temperature : public BoundedFloat
{
public:
Temperature(const float v) : BoundedFloat(v, my_data) {}
private:
static const Data my_data;
};
const Temperature::Data Temperature::my_data{ -40.0f, 80.0f };
这里只有一个对派生类数据值的初始化,它们几乎自然地在“基类”中;只是您需要将它们称为data.Min
和data.Max
。当有大量数据(每个类恒定)时,通常使用此模式,但是您当然也可以仅将其与少量数据一起使用。此处的编码成本与传递单个基本值相当,甚至更低,并且程序的运行时成本可能会有所上升或下降,具体取决于。
答案 2 :(得分:1)
您可以使用基类的模板并将派生类型用作基类模板的类型来获得所需的内容。这用于启用静态多态性,称为Curiously recurring template pattern (CRTP),但在这种情况下,我将其用作标记,因此每个派生类在基类中都可以拥有自己的一组静态数据成员。将基类更改为
template<typename Derived>
class BoundedFloat
{
public:
BoundedFloat(const float v) : Value(v) {}
static float getMax() { return Max; }
static float getMin() { return Min; }
protected:
static const float Min;
static const float Max;
float Value;
};
表示BoundedFloat<Derived>
拥有自己的Min
和Max
。因此我们像这样从BoundedFloat
派生
class Temperature : public BoundedFloat<Temperature>
{
public:
Temperature(const float v) : BoundedFloat(v) {}
};
然后我们必须定义想要的值
template<>
const float BoundedFloat<Temperature>::Min = -40.0f;
template<>
const float BoundedFloat<Temperature>::Max = 80.0f;
您可以看到此live example
中运行的代码请注意,如果您想在派生类中使用基类静态成员,则需要使用脱节定义。之所以必须这样做,是因为如果函数主体在派生类中,则它需要隐式实例化静态成员,而由于显式实例化在该类之后,因此我们不可能发生这种情况。
答案 3 :(得分:0)
根据@NathanOliver的建议,这是我目前所掌握的。
它满足我的需求:
这种方法有什么严重的错误吗?
BaseTypes.h
namespace Common
{
template<typename Base>
class BoundedFloat
{
public:
BoundedFloat(const float v) : Value(v) {}
// Common methods that read Min, Max, Value
void displaySummary() const;
bool withinBounds() const;
// bool breachedLowerThreshold() const;
// bool breachedUpperThreshold() const
protected:
static const float Min;
static const float Max;
float Value;
};
template <typename Base>
void BoundedFloat<Base>::displaySummary() const
{
std::cout <<
"Min = " << Min << ", "
"Max = " << Max << ", "
"Value = " << Value << std::endl;
if (withinBounds())
{
cout << "within bounds" << endl;
}
else
{
cout << "outwith bounds" << endl;
}
}
template <typename Base>
bool BoundedFloat<Base>::withinBounds() const
{
return ((Value >= Min) && (Value <= Max));
}
}
SensorReading.h
#pragma once
#include "BaseTypes.h"
namespace Common
{
class SensorReading: public BoundedFloat<SensorReading>
{
public:
SensorReading(const float v) : BoundedFloat(v) {}
};
template<>
const float BoundedFloat<SensorReading>::Min = -2.0f;
template<>
const float BoundedFloat<SensorReading>::Max = 7.5f;
}
温度.h
#pragma once
#include "BaseTypes.h"
namespace Common
{
class Temperature : public BoundedFloat<Temperature>
{
public:
Temperature(const float v) : BoundedFloat(v) {}
};
template<>
const float BoundedFloat<Temperature>::Min = -40.0f;
template<>
const float BoundedFloat<Temperature>::Max = 80.0f;
}
main.cpp
int main()
{
Temperature temperature{ 80.0f };
temperature.displaySummary();
SensorReading sensorReading{ 72.5f };
sensorReading.displaySummary();
return 0;
}