当基类想要访问继承类的成员时

时间:2014-08-08 23:21:38

标签: c++ class inheritance nodes edges

这是我的情况:

我正在用C ++编写一个由节点和边缘组成的数据结构。 节点通过边连接到其他节点。

我有不同类型的节点,例如文本节点或int节点。 文本节点连接到文本节点,int节点连接到int节点。 我使用继承来实现不同类型的节点,因为它是有道理的: 从根本上说,所有节点都连接到其他节点,因此Node是基类, 和TxtNode,IntNode是继承的类,它们共享节点的基本属性。

但是,当我尝试从继承节点获取连接的继承节点时,这会给我带来问题,因为在基类Node中定义了提取功能(检索连接到调用节点的特定节点的功能)。例如,从TextNode调用此获取函数会返回TextNode的基本版本,该版本缺少额外信息。

我不确定在这里做什么是合理的编码实践。 我选择以这种方式对其进行编码,因为我必须为所有不同类型的节点定义不同的连接获取功能,这似乎没有意义。

如果有任何我可以披露的信息,请告诉我。

这是我的代码,我正在尝试打印一个继承节点的合作伙伴,但它会导致打印基本节点。

Node.cpp

#include "Node.h"
#include "Edge.h"

#include "common.h"

#include <vector>
#include <cassert>
#include <cstddef>
#include <stdint.h>
#include <iostream>

Node::Node() {
    id = (intptr_t)this;
    edges.clear();
}

int Node::connect(Node* dst) {
    // establish link between calling node
    // and dst node, first linkage will
    // edge between each other, links after
    // increments strength. returns number of
    // links

    // fetch edge connecting this node and 
    // dst node
    Edge* edge = findDstEdge(dst);

    // if the branch isn't established yet,
    // then make connection
    if (edge==NULL) {
        establishConnection(dst, 1);
        return 0;
    } else {
        edge->strengthenConnection();
        return 1;
    }

}

Edge* Node::findDstEdge(Node* dst) {
    // fetches edge corresponding
    // to destination node

    // walk through vector of edges to find
    // edge connecting to dst

    vector<Edge*>::iterator iter = edges.begin();

while(iter!=edges.end()) {
    Edge* e = *iter;
    Node* partner = e->getPartner(this);
    if (partner->getID() == dst->getID())
        return e;
    iter++;
    }
    // not found
    return NULL;
}

void Node::establishConnection(Node* dst, int str) {
    // low level node addition

    // establish a new edge between
    // nodes which don't know each other
    Edge* e = new Edge(this, dst, str);
    this->manuallyConnect(e);
    dst->manuallyConnect(e);
}

void Node::manuallyConnect(Edge* e) {
    edges.push_back(e);
}

ostream& operator<<(ostream& stream,Node n) {

    vector<Edge*>::iterator iter = n.edges.begin();

    while(iter!=n.edges.end()) {
        Edge* e = *iter;
        stream << *e << endl;
        iter++;
    }

    return stream;
}

Node.h

#ifndef _NODE_H_
#define _NODE_H_

#include "common.h"

#include <vector>
#include <string>
#include <stdint.h>

class Edge;

using namespace std;

class Node {  

  protected:
    vector<Edge*> edges;
    intptr_t id;

  public:
    Node();

    // manipulation
    void establishConnection(Node* dst,
           int str);
    int connect(Node* dst);
    Edge* findDstEdge(Node* dst);

    // fetchers
    intptr_t getID() {return id;}
    vector<Edge*> getEdges() {return edges;}

    void manuallyConnect(Edge* e);

    friend ostream& operator<<(ostream& stream, Node n);
};

#endif

TxtNode.cpp

#include "TxtNode.h"
#include "Edge.h"

#include "common.h"

#include <iostream>

TxtNode::TxtNode(char c): Node()  {
    _c = c;
}

ostream& operator<<(ostream& stream, TxtNode tn) {
    // print out character of this TxtNode
    stream << "char: " << tn._c << endl;
    stream << "id: " << tn.id << endl;

    // print out all connections and its
    // strength
    vector<Edge*>::iterator iter = tn.edges.begin();

    while(iter!=tn.edges.end()) {
        Edge* e = *iter;
        stream << *e << endl;
        iter++;
    }

    return stream;
}

Edge.cpp

#include "Edge.h"
#include "Node.h"

#include "common.h"

#include <cassert>
#include <iostream>

using namespace std;

Edge::Edge(Node* a, Node* b, int str) {
    node_a = a;
    node_b = b;
    strength = str;
}

void Edge::strengthenConnection() {
    strength++;
}

Node* Edge::getPartner(Node* src) {
    uint src_ID = src->getID();
    if (node_a->getID() == src_ID)
        return node_b;
    else if (node_b->getID() == src_ID)
        return node_a;
    assert(false);
}

ostream& operator<<(ostream& stream, Edge e) {
    stream << "strength: "
           << e.strength
           << endl;
    stream << "node_a: "
           << e.node_a->getID()
           << endl;
    stream << "node_b: "
           << e.node_b->getID()
           << endl;
    return stream;
}

目前我只需要打印ID为intptr_t的代码, 因为我发现我无法从基类访问继承的类成员。

我倾向于从基类访问继承的类的成员,因为边类处理基类节点。

2 个答案:

答案 0 :(得分:1)

你写

  

文本节点连接到文本节点,int节点连接到int节点。

然后,您可以非常简单地将Node_定义为类模板:

template< class Value >
struct Node_
{
    vector<Node_*>  connected_nodes;
    Value           value;
};

换句话说,使用编译时多态,而不是动态多态,以便在编译时获得相关的类型信息。

那就是说,看看Boost.Graph,看看它是否不适合你的需求。

答案 1 :(得分:1)

类代码将是一件好事。

根据您的说法,您不要将获取功能声明为虚拟。

这是关于虚拟/非虚拟功能如何工作的非常快速的示例

class baseNode {
 public:
    int fetch() { printf "fetched from base";};
}

class intNode : public baseNode {
 public:
    int fetch() { printf "fetched from derived int";};
}

class txtNode : public baseNode {
 public:
    int fetch() { printf "fetched from derived txt";};
}

以下代码

baseNode * ptr = new intNode();
ptr->fetch();

将打印“从基地获取”

但是如果你声明fetch函数是虚拟的:

class baseNode {
 public:
     virtual int fetch() { printf " fetched from base";};
}

然后相同的代码将打印“从衍生的int中获取”。