强制转换基类保护方法的返回指针的替代方法

Alternative to casting return pointer of base class protected method?

本文关键字:方法 指针 返回 基类 保护 转换      更新时间:2023-10-16

我想出了一个使用受保护嵌套结构的类,打算派生类来增强结构。为此,我声明了一个用于分配结构的虚拟方法。

现在,基类在processSomeData中做了一些不小的工作,我希望派生类重用它。

这会导致以下结果:

class A
{
public:
    virtual void doProcessing(); // uses processSomeData()
protected:
    struct someData
    {
        virtual ~someData() {};
        // data members
    };
    virtual someData* processSomeData(); // uses allocateSomeData()
    virtual someData* allocateSomeData();
};
class B : public A
{
public:
    virtual void doProcessing()
    {
        derivedData* myData =
            static_cast<derivedData*>(A::processSomeData()); // *** seems a little suspect
        // do work on the additional data members in myData
    }
protected:
    struct derivedData : public someData
    {
        // more data members
    };
    virtual derivedData* allocateSomeData();
};

因为allocateSomeData被覆盖了,所以我知道A::processSomeData返回指向derivedDatasomeData*,所以static_cast绝对是安全的。

也就是说,感觉我应该从一个基础铸造到派生,而其他一切似乎都很犹太洁食。
有没有更好/正确的方法来做到这一点,而不使用石膏?还是我必须重新设计我的类/结构?

这是因为编译器不确定processSomeData使用allocateSomeData来创建someData结构。就编译器所知的 someData,从 processSomeData 返回的很可能只是 someData 的一个实例。派生数据是一些数据,但不是相反。

虽然模板参数是一个很好的方法,但让我投票支持另一种解决方案。

首先,我们将processSomeData移动到嵌套的someData结构中,使其保持虚拟。它的实现执行了someData及其派生类共有的所有工作。我们还有一个新的受保护的虚拟函数,称之为 furtherProcess .对于someData它是空的。对于每个派生类,它处理所需的任何内容。someData::processSomeData()的最后一行是 furtherProcess() .

这种在最后使用钩子函数的做法避免了原始设置中隐含的 Call Super 代码气味,这在这些向下的投射中经常出现。

我通过将嵌套类移出并使其成为模板参数来解决此问题,因为我永远不会同时使用someDataderivedData

struct someData
{
    virtual ~someData() {};
    // data members
};
template <typename DataType = someData>
class A
{
public:
    virtual void doProcessing(); // uses processSomeData()
protected:
    typedef DataType myDataType;
    virtual myDataType* processSomeData(); // uses allocateSomeData()
    virtual myDataType* allocateSomeData();
};
struct derivedData : public someData
{
    // more data members
};
class B : public A<derivedData>
{
public:
    virtual void doProcessing()
    {
        myDataType* myData = A::processSomeData();
        // do work on the additional data members in myData
    }
protected:
    virtual myDataType* allocateSomeData();
};

虽然嵌套类看起来像是封装信息的好方法,但它似乎不值得在类型安全和性能之间进行权衡。

这个

答案是在我做出改变后不久发现的,似乎在某种程度上证明了这个决定的正确性。