为什么嵌套 class 对外部 class 不可见

why nested class not visible to outer class

我被嵌套的问题弄糊涂了class

#ifndef MINIGRAPH_H_
#define MINIGRAPH_H_
#include<vector>
#include<list>
#include<iostream>
template <typename VEX,typename EDGE>
class MiniGraph
{
public:
    class _Node
    {
    public:
        VEX _Vex;
        EDGE _Edge;
         _Node* next;
    };
    MiniGraph() {};
    MiniGraph(int vex_num);
    void add(VEX from, VEX to, EDGE Edge);
    //void display();
private:
    std::vector<void*> _VecNode;
    _Node* NewNode(VEX vex) { _Node* ptr = new _Node;ptr->_Vex = vex;return ptr; }
    _Node* NewNode(VEX vex, EDGE edge) { _Node* ptr = new _Node;ptr->_Vex = vex;ptr->_Edge = edge;return ptr; }

};
template <typename VEX, typename EDGE>
MiniGraph<VEX, EDGE>::MiniGraph(int vex_num)
{
    int i = 0;
    for (i = 0;i < vex_num;i++)
    {
        struct Node *ptr_tmp = new _Node;
        ptr_tmp->next = NULL;
        _VecNode.push_back(ptr_tmp);
    }
}
template <typename VEX, typename EDGE>
void MiniGraph<VEX, EDGE>::add(VEX from, VEX to, EDGE edge)
{
    int i;
     _Node* ptr_node = NULL;
    for (i = 1;i < _VecNode.size();i++)
    {
        ptr_node = (_Node*)_VecNode[i];
        if (ptr_node->_Vex == from)
            break;
    }
    if (i == _VecNode.size())
    {
        ptr_node = NewNode(from);
        _VecNode.push_back(ptr_node);
    }
    ptr_node = NewNode(from, edge);
    **ptr_node->next = (_Node*)_VecNode[i]->next;//insert node from head**
    _VecNode[i]->next = ptr_node;
}

使用

编译时
#include "MiniGraph.h"
void main()
{
    MiniGraph<int, double> hh;
    hh.add(1, 2, 0.1);
    hh.add(1, 3, 0.2);
    hh.add(2, 3, 0.3);
}

ptr_node->next = (_Node*)_VecNode[i]->next;//insert node from head 中触发错误 说 ->next left 必须指向 class/struct/union/generic 类型; 但是声明了_Node。我试图用结构替换class,但它触发了同样的错误。 好像声明不是visible.how我应该解决这个问题吗?

正如@WhozCraig 在上面的评论中提到的,你有一个 void* 的向量,而不是 Node* 的向量。因此没有名为 next 的成员。您可以 type_cast void*Node* 到 "fix" 的问题,但您会大吃一惊。

问题从您的 main 函数开始。

int main()
{
    MiniGraph<int, double> hh;

此代码将调用 MiniGraph class 的默认构造函数。这意味着不会创建 Nodes 并且 Node* 的向量将为空(即 std::vector<Node*>::size = 0.

然后调用add函数:

hh.add(1, 2, 0.1);

add 函数中发生以下情况:

void add(VEX from_, VEX to_, EDGE edge_)
{
    std::size_t i = 0;

    for (i=1; i<node_ptrs.size(); i++)
    {
        if (node_ptrs[i]->vex == from_)
            break;
    }

在第一次调用add()之后,向量size = 0,但是i = 1。那是因为你在 for 循环中初始化了 i=1

然后你检查是否i == vector::size.

    Node *tmp = nullptr;
    if (i == node_ptrs.size())
    {
        tmp = NewNode(from_);
        node_ptrs.push_back(tmp);
    }

上面的 if 语句永远不会被执行,因为 i = 1vector::size = 0.

最后,您执行以下操作:

    tmp = NewNode(from_, edge_);
    tmp->next = node_ptrs[i]->next; // this fails because your vector size is 0!
    node_ptrs[i]->next = tmp;

第一行有效。 tmp 是指向新创建的 NodeNode*。行。然后程序因分段错误而失败,因为 tmp->next 试图浅拷贝向量的 i 元素中的指针。现在记住 i = 1 并且向量仍然是空的,即 vector::size = 0。没有要从中复制的 node_ptrs[1] 元素。这就是它崩溃的原因。

以上代码示例:https://rextester.com/DTODK86272

你原来的代码还有很多问题要考虑... 例如:

  • 如果只有一个指针指向某个 Node,则使用 unique_ptr。您仍然可以从 unique_ptr 读取其他指针,但它们将无法执行任何其他操作。
  • 编写将指针初始化为 nullptr 的构造函数,并对 vexedge 成员调用零初始化。
  • 避免使用 int 作为数组索引。如果有人决定使用负数作为函数参数怎么办?
  • 在您的实现中,您必须在开始执行任何其他操作之前检查向量是否为空。如果向量为空会怎样?