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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7190952/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:34:42  来源:igfitidea点击:

Access child members within parent class, C++

c++inheritance

提问by unexplored

I am facing a situation where I need to access child member variables inside the parent class. I know this is against OO principles but I have to deal with a scenario where hundreds of classes are inheriting from one and along the way half of them stopped using one of the parents variable, and declared and used their own (there was need to switch from int to int[] and apparently the person who did that didn't take in consideration to apply this changes in the parent class instead).

One option is to have a virtual function to deal with it, but this means I have to change the code in hundreds of file/objects and test each one of them. Hence I thought if it is possible to use some old school C pointer magic to gain access to this variables inside the parent method, this will eliminate the need of hundreds of virtual functions.

Basically this is what I want to achieve:

我面临一种情况,我需要访问父类中的子成员变量。我知道这违反 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;
}

Please let me know if this is even possible. If yes how do I achieve that.
Other suggestions are welcomed, but keep in mind that I'd like to make changes only in the parent class.
TIA.

请让我知道这是否可能。如果是,我如何实现这一目标。
欢迎其他建议,但请记住,我只想在父类中进行更改。
TIA。

采纳答案by Chris Jester-Young

The only clean way is to use the virtual function approach.

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

If the Parentclass has at least one virtual function (not necessarily DoSomething), there's also a yucky way to do it:

如果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
}

(If Parenthas no virtual functions, then the dynamic_castwon't work. Though, any class designed to be inherited from should have at least one virtual function, even if it's just the destructor.)

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

回答by Simon

Probably CRTP helps here:

可能 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();
    }
}

I changed the code that it is compilable - probably not what you're requirements are - but then provide a better (=compilable) sample code.

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

回答by Stamen Rakov

If you're allowed to change your child classes source code, you can do something like that:

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

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

Otherwise, if your object has virtual table (at least one virtual method), you can use static_cast() in combination with C++11 typeid, because it's about three times faster than dynamic_cast:

否则,如果您的对象具有虚拟表(至少一个虚拟方法),则可以将 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;
    }
};

回答by gospes

I dont get the downvotes for the static cast. The following works:

我没有得到静态演员的反对票。以下工作:

#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();
}

Just make sure to put the declarations of the A functions after the definition of the B class. You can differentiate between child classes because the static cast will return not NULL if you have found the right child. I find this approach also beneficial because the Child class (B) is barely changed.

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

回答by apokryfos

Would making an intermediate abstract class that contains the childMember you need to access be an option?

制作一个包含您需要访问的 childMember 的中间抽象类是一种选择吗?

If so:

如果是这样的话:

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() { }
}

回答by fdlm

Apparently you have some subset of derived classes which utilise childMember. For these classes you have some method "DoSomething()" which can be called. I guess for all other derived classes the method DoSomething()is not applicable. Why don't you create another abstraction level for this set of derived classes?

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

class Parent
{
    // no DoSomething()
}

class ChildMemberClasses : Parent
{
    int childMember;

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

class ChildWithChildMember : ChildMemberClasses
{
    // other stuff
}

If DoSomething()has some meaning for classes without childMember, you can still define the it as virtual method in Parent. Like this:

如果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
}

回答by Praetorian

You can use the curiously recurring template patternto achieve this.

您可以使用奇怪的重复模板模式来实现这一点。

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

回答by Oliver Charlesworth

There is no safe, robust method of doing this with pointers. You could hack around with clever pointer offsets, but this would rely on the childMemberappearing in the same location in all of the child classes.

没有安全、健壮的方法可以用指针来做到这一点。您可以使用巧妙的指针偏移来解决问题,但这将依赖于childMember出现在所有子类中的相同位置。

回答by john

static_cast<Child*>(this)->childMember = 0;should work.

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