访问父类C ++中的子成员

时间:2011-08-25 13:11:13

标签: c++ inheritance

我面临的情况是我需要在父类中访问子成员变量。我知道这是违反OO原则的,但是我必须处理一个场景,其中有数百个类继承自一个类,并且其中一半停止使用其中一个父变量,并声明并使用它们自己(需要切换)从int到int [],显然那个人没有考虑在父类中应用这些更改。

一种选择是使用虚拟函数来处理它,但这意味着我必须更改数百个文件/对象中的代码并测试它们中的每一个。因此,我认为如果可以使用一些旧的学校C指针魔术来获取父方法内部的这些变量,这将消除数百个虚函数的需要。

基本上这就是我想要实现的目标:

class Parent
{
    void DoSomething()
    {
        // This is what I need
        childMember = 0;
    }
}

class Child1 : Parent
{
    int childMember;
}

class Child2 : Parent
{
    int childMember;
}

如果可能,请告诉我。如果是,我该如何实现。
欢迎其他建议,但请记住,我只想在父类中进行更改。
TIA。

9 个答案:

答案 0 :(得分:7)

唯一干净的方法是使用虚函数方法。

如果Parent类至少有一个虚函数(不一定是DoSomething),那么还有一种令人讨厌的方法:

void DoSomething() {
    if (Child1* child = dynamic_cast<Child1*>(this)) {
        child->childMember = 0;
    } else if (Child2* child = dynamic_cast<Child2*>(this)) {
        child->childMember = 0;
    } // and so on, and so forth
}

(如果Parent没有虚函数,则dynamic_cast将不起作用。但是,任何设计为继承的类都应该至少有一个虚函数,即使它只是析构函数。)

答案 1 :(得分:4)

CRTP可能有帮助:

struct Parent
{
    virtual void DoSomething() = 0;
};

template <typename Derived>
struct ParentProxy : Parent
{
    virtual void DoSomething()
    {
        Derived* p = dynamic_cast<Derived*>(this);
        p->childMember = 27;
    }
};

struct Child1 : ParentProxy<Child1>
{
    int childMember;
};

struct Child2 : ParentProxy<Child2>
{
    int childMember;
};

int main()
{
    Child1 child1;
    Child2 child2;

    Parent* objects[] = { &child1, &child2 };
    const int objectCount = sizeof(objects) / sizeof(objects[0]);
    for (int index = 0; index < objectCount; ++index)
    {
        Parent* parent = objects[index];
        parent->DoSomething();
    }
}

我更改了可编译的代码 - 可能不是您的要求 - 但随后提供了更好的(=可编译的)示例代码。

答案 2 :(得分:2)

如果您允许更改子类源代码,则可以执行以下操作:

class Parent
{
public:
    void DoSomething()
    {
        getMember() = 0;
    }
    virtual int & getMember() = 0;
};

class Child1 : public Parent
{
    int childMember;
public:
    int & getMember()
    {
        return childMember;
    }
};

class Child2 : public Parent
{
    int childMember;
public:
    int & getMember()
    {
        return childMember;
    }
};

否则,如果您的对象具有虚拟表(至少一个虚方法),则可以将static_cast()与C ++ 11 typeid结合使用,因为它比dynamic_cast快三倍:

#include <typeinfo>

class Parent
{
public:
    virtual void DoSomething();
};

class Child1 : public Parent
{
public:
    int childMember;
};

class Child2 : public Parent
{
public:
    int childMember;
};

void Parent::DoSomething()
{
    if (typeid(Child1) == typeid(*this))
    {
        auto child = static_cast<Child1*>(this);
        child->childMember = 0;
    }
    else if (typeid(Child2) == typeid(*this))
    {
        auto child = static_cast<Child2*>(this);
        child->childMember = 0;
    }
};

答案 3 :(得分:1)

我没有得到静态演员的downvotes。以下作品:

#include <stdio.h>
class B;
class A {
    public:
        A();
        void print();
    private:
        B *child;
};

class B : public A {
    friend class A;
    public:
        B();
    private:
        int value;
};

A::A(){
    child = static_cast<B*>(this);
}

void A::print(){
    printf("value = %d\n", child->value);
}

B::B(){
    value = 10;
}

int main(){
    B b;
    b.A::print();
}

确保在B类的定义之后放置A函数的声明。您可以区分子类,因为如果找到了正确的子项,静态强制转换将不返回NULL。我发现这种方法也很有用,因为Child类(B)几乎没有改变。

答案 4 :(得分:0)

显然,您有一些利用childMember的派生类子集。 对于这些类,您可以使用一些可以调用的方法“DoSomething()”。我想对于所有其他派生类,方法DoSomething() 不适用。为什么不为这组派生类创建另一个抽象级别?

class Parent
{
    // no DoSomething()
}

class ChildMemberClasses : Parent
{
    int childMember;

    void DoSomething()
    {
        // code that uses childMember
    }
}

class ChildWithChildMember : ChildMemberClasses
{
    // other stuff
}

如果DoSomething()对没有childMember的类有一定意义,您仍然可以在Parent中将其定义为虚拟方法。像这样:

class Parent
{
    virtual void DoSomething()
    {
        // code that does not use childMember
    }
}

class ChildMemberClasses : Parent
{
    int childMember;

    void DoSomething()
    {
        // code that uses childMember
    }
}

class ChildWithChildMember : ChildMemberClasses
{
    // other stuff
}

答案 5 :(得分:0)

您可以使用curiously recurring template pattern来实现此目标。

template<typename T>
class Parent
{
    void DoSomething()
    {
        // This is what I need
        T::childMember = 0;
    }

    virtual ~Parent() {}
};

class Child1 : Parent<Child1>
{
  int childMember;

  friend class Parent<Child1>;
};

答案 6 :(得分:0)

是否需要创建一个包含您需要访问的childMember的中间抽象类?

如果是这样的话:

class Parent
{
    virtual void DoSomething() //Parent must be a polymorphing type to allow dyn_casting
    {
        if (AbstractChild* child = dynamic_cast<AbstractChild*>(this)) {
            child->childMember = 0;
        } else //Its not an AbstractChild
    }
}

class AbstractChild : Parent 
{ 

     int childMember; 
     virtual void DoSomething() = 0;
}

class Child1 : AbstractChild {
     virtual void DoSomething() { }
}

答案 7 :(得分:-1)

使用指针执行此操作没有安全,可靠的方法。您可以使用聪明的指针偏移进行攻击,但这将依赖于出现在所有子类中相同位置的childMember

答案 8 :(得分:-2)

static_cast<Child*>(this)->childMember = 0;应该有用。