C ++-在派生类中

时间:2019-04-03 12:30:51

标签: c++ constructor static

我们正在尝试在项目中限制primitive types,在该项目中,我们可以检查派生类的实例的数据值是否在有效范围内(minmax成员变量,受保护以class为基础的class)。

我的问题是,有没有一种方法可以静态地初始化派生类的minmax变量,而不是每次实例化派生的{ {1}}。

class中,这将在静态初始化块中,但是我不确定如何在class中进行此操作。

我知道我可以在派生的C#中初始化它们,但是每次这样做似乎很浪费。

我想我正在寻找在基类中声明但随后在派生类中静态定义的抽象数据成员。

C++

4 个答案:

答案 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类型的对象,则每个对象都有自己的MinMax,因此所有这些对象都需要在某个时刻初始化。此外,除非您以某种方式让它知道,基类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.Mindata.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>拥有自己的MinMax。因此我们像这样从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的建议,这是我目前所掌握的。

它满足我的需求:

  • 在基类中声明为的公用值
  • 随后在派生类中定义的通用值只有一次,这使构造函数更加整洁
  • 基类中的
  • 可以使用派生的 const值的常见方法

这种方法有什么严重的错误吗?

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;
}