关于c ++:替代基类保护方法的转换返回指针?

Alternative to casting return pointer of base class protected method?

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

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

这将导致以下情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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返回的someData*指向derivedData,所以静态投射绝对安全。

这就是说,当其他一切看起来都很干净的时候,我觉得有点不该从一个基地扔到衍生基地。有没有更好/正确的方法来做到这一点,而不使用石膏?还是必须重新设计类/结构?


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

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

这种在末尾使用hook函数可以避免a href="https://en.wikipedia.org/wiki/call_super"rel="nofollow">call super/aa代码在原始设置中散发出暗含的气味,这在这些降级中经常会看到。


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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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();
};

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

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