从父指针访问子数据

Accessing child data from parent pointer

本文关键字:数据 访问 指针      更新时间:2023-10-16

假设我有一个我无法更改的父班,并且它具有孩子将使用的函数。这两个孩子相似,但使用不同的数据。在此示例中,假设一个包含一个带有关联方法的数组,另一个包含一个带有关联方法的2D数组。

struct Parent {
    Parent* DoSomethingWithChildren(Parent &other)
};
struct Child1 : Parent {
   int a[x];
};
struct Child2 : Parent {
   int b[x][y];
};

现在说我创造了两个孩子。

Parent* child1 = new Child1();
Parent* child2 = new Child2();
child1.DoSomethingWithChildren(child2);

dosomethingwithChildren函数应该能够使用" this"指针访问Child1,如果我没记错的话,并且由于Child2被传递给该功能,也应该可以访问。

问题在于,在dosomethingwithchildren函数中,我只能从父访问数据和功能。

有什么办法可以做到这一点吗?也许使用模板?

您的问题有几个解决方案。

动态铸造

class Parent {
    public:
        Parent* DoSomethingWithChildren(Parent& other) {
            Child* childPointer = dynamic_cast<Child>(&other);
            if(childPointer) {
                // now you have Child class API
            } else {
                // this was clearly not a Child object
            }
        }
};

虚拟方法只需查找它们;)


,但我主要认为您的概念是错误的。这样做会更好:

class Parent {
    virtual void doSomethingWithParent(Parent* parent) = 0;
};
class Child1 : public Parent {
    void doSomethingWithParent(Parent* parent) {
        //you now have Child1 API and parent object
    }
};
int main() {
    Parent parent;
    Child1 child;
    Child2 child2;
    child1.doSomethingWithParent(parent);
    child2.doSomethingWithParent(parent);
}

这样,每个孩子都可能有不同的过载。

派生的类应实现细节,而不是基本类以管理所有派生的类别。这简直是很差的。

您正在创建指向基类的指针,并在将构造函数用于其继承类之一时创建新的内存。当您调用属于基类的函数以使用其派生的类之一来完成某些派生类可以访问该基类的受保护或公共成员变量和功能的函数时,编译器可能不知道要明确工作哪种类型。如果您确切地知道您将拥有多少种不同的派生类型,那么在您的基类中,您可以对每种类型进行公开枚举,并将其作为私人成员存储。这是一个示例:

class Node {
public:
    enum TYPE {
      TYPE_ONE,
      TYPE_TWO,
    };
private:
    TYPE m_type;
public:
    explicit Node( Node::TYPE type ) : m_type( type ) {}
    Node* doSomeWork( Node* other );
}; // Node
Node* Node::doSomeWork( Node* other ) {        
    Node* pNode = dynamic_cast<Node*>( other );
    switch ( m_type ) {
        case TYPE_ONE: {
            // Do Work Here
            return pNode;
        }
        case TYPE_TWO: {
            // Do Work Here
            return pNode;
        }
        default: {
            // If derived type not defined either throw exception
            // or return a nullptr
            return pNode = nullptr;
        }
    }
}
class Type1 : public Node {
    // Member Variables Here
public:
    Type1() : Node( TYPE_ONE ) {}
};
class Type1 : public Node {
    // Member Variables Here
public:
    Type2() : Node( TYPE_TWO ) {}
};

在此示例中,当您调用您的函数进行工作时,将根据类型做出决定,并将派生类型的指针施放在基本类型工作的指针上,然后返回指针。

如果您确切知道自己拥有多少个派生类型,这将起作用。如果派生类型的数量未知,那么我建议在基类中纯粹将Dowork函数声明为虚拟函数,这使得基类使您无法创建它的实例,并且任何派生的类都必须实现纯粹是虚拟的功能,您可以让每个类覆盖它。

class Node {
public:
    virtual ~Node(){}
    virtual Node* doSomeWork( Node* other ) = 0;  
protected:
    Node(){}
};
class Type1 : public Node {
public:
    // Must Be Implemented But Can Be Override
    Node* doSomeWork( Node* other ) override;       
};
class Type2 : public Node {
public:
    // Must Be Implemented But Can Be Override
    Node* doSomeWork( Node* other ) override;
};

Dynamic_cast的概念仍然适用于您的DosomeWork()函数,但是由于实现在类实现上实现,因此不需要开关语句!这样做任何派生类都必须声明并实现此功能。现在,如果特定的派生类型对此功能没有用,您仍然必须定义它,但是您将使身体的内容留为空。