Когда базовый класс хочет получить доступ к члену унаследованного класса

это моя ситуация:

Я пишу структуру данных в C ++, которая состоит из узлов и ребер.
Узлы связаны с другими узлами с помощью ребер.

У меня есть разные типы узлов, такие как текстовые узлы или int-узлы.
Текстовые узлы связаны с текстовыми узлами, а int-узлы связаны с int-узлами.
Я использую наследование для реализации различных типов узлов, потому что это имеет смысл:
по сути, все узлы связаны с другими узлами, поэтому Node является базовым классом,
и TxtNode, IntNode являются унаследованными классами, которые имеют фундаментальное свойство узла.

Однако это вызывает у меня проблемы, когда я пытаюсь извлечь подключенный унаследованный узел из унаследованного узла, поскольку функция извлечения (функция, которая извлекает определенный узел, связанный с вызывающим узлом) определена в узле базового класса. Например, вызов этой функции извлечения из 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;
}

В настоящее время у меня просто есть код для печати идентификатора, который является intptr_t,
потому что я обнаружил, что не могу получить доступ к члену унаследованного класса из базового класса.

Я склонен получить доступ к члену унаследованного класса из базового класса, потому что крайний класс имеет дело с классом базового узла.

2

Решение

Код классов был бы неплохо иметь.

Из того, что вы говорите, вы не объявляете функцию извлечения виртуальной.

Вот очень быстрый пример того, как работают виртуальные / не виртуальные функции

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

Напечатает «взято из базы»

Но если вы объявите функцию извлечения виртуальной:

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

Затем тот же код напечатает «извлечено из производного int».

1

Другие решения

Ты пишешь

« Текстовые узлы связаны с текстовыми узлами, а int-узлы связаны с int-узлами.

Тогда вы можете очень просто определить Node_ как шаблон класса:

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

Другими словами, используйте полиморфизм времени компиляции, а не динамический полиморфизм, чтобы иметь доступ к соответствующей информации типа во время компиляции.

Тем не менее, посмотрите на Boost.Graph и посмотрите, не подходит ли он вашим потребностям.

1

По вопросам рекламы [email protected]