使用模板的C ++类

时间:2018-04-04 11:54:23

标签: c++ data-structures graph

我在C ++中实现了一个简单定制的图形数据结构。我实现的第一个“类”是“节点”或装饰节点。经过一些研究,我从一个班级转到另一个班级,就像这样。

template <typename T>
class Node {
public:

Node                    ( T element )           {this->_element=element;}
//Setters
void    heuristic       ( double heuristic )    {this->_heuristic=heuristic;}
void    visited         ( bool visited )        {this->_visited=visited;}
void    element         ( T element )           {this->_element=element;}
void    incrementOrder  ()                      {this->_order++;}
void    decrementOrder  ()                      {this->_order--;}

//Getters
int     order           ()                      {return this->_order;}
double  heuristic       ()                      {return this->_heuristic;}
T       element         ()                      {return this->_element;}
bool    isVisited       ()                      {return this->_visited;}

protected:

double  _heuristic;
bool    _visited;
T       _element;
int     _order;

};

问题来自于实施“Edge”课程的时候了。我虽然喜欢这样的东西:

#include "Node.hpp"

template <typename T>
class Edge {
public:

Edge    (Node<T>& leftNode, Node<T>& rightNode) {this->_leftNode=leftNode;this->_rightNode=rightNode;}    

Node<T> leftNode    ()                          {return this->_leftNode;}
Node<T> rightNode   ()                          {return this->_rightNode;}

void    leftNode    (Node<T> leftNode)          {this->_leftNode=leftNode;}
void    rightNode   (Node<T> rightNode)         {this->_rightNode=rightNode;}

protected:

Node<T> _leftNode;
Node<T> _rightNode;

};

就是这样,构造函数给了我一些问题,经过研究后我认为是因为“Node”不是真正的类,而且“Edge”也被转换为模板。

问题是¿无论如何,Edge可以使用此节点而无需转换为模板吗?

感谢您的时间。

//编辑#1

我希望实现尽可能通用,这就是为什么我认为Edge类应该具有Node类型的属性。

主要栏目如下:

int main(){

    Node<int> *n1 = new Node<int>(1);
    Node<int> *n2 = new Node<int>(2);

    Edge<int> *e = new Edge<int>(n1, n2);

    return 0;
}

错误消息是:

g++ -Wall --std=c++11 -Iinclude/ src/Main.cpp -o exe/main
src/Main.cpp: In function ‘int main()’:
src/Main.cpp:11:16: warning: unused variable ‘e’ [-Wunused-variable]
     Edge<int> *e = new Edge<int>(n1, n2);
                ^
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp: In instantiation of ‘Edge<T>::Edge(Node<T>*, Node<T>*) [with T = int]’:
src/Main.cpp:11:40:   required from here
include/Edge.hpp:8:53: error: no matching function for call to ‘Node<int>::Node()’
     Edge    (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=ri
                                                     ^
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:17:5: note: candidate: Node<T>::Node(T) [with T = int]
     Node                    ( T element )           {this->_element=element;}
     ^
include/Node.hpp:17:5: note:   candidate expects 1 argument, 0 provided
include/Node.hpp:14:7: note: candidate: constexpr Node<int>::Node(const Node<int>&)
 class Node {
       ^
include/Node.hpp:14:7: note:   candidate expects 1 argument, 0 provided
include/Node.hpp:14:7: note: candidate: constexpr Node<int>::Node(Node<int>&&)
include/Node.hpp:14:7: note:   candidate expects 1 argument, 0 provided
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:53: error: no matching function for call to ‘Node<int>::Node()’
     Edge    (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=ri
                                                     ^
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:17:5: note: candidate: Node<T>::Node(T) [with T = int]
     Node                    ( T element )           {this->_element=element;}
     ^
include/Node.hpp:17:5: note:   candidate expects 1 argument, 0 provided
include/Node.hpp:14:7: note: candidate: constexpr Node<int>::Node(const Node<int>&)
 class Node {
       ^
include/Node.hpp:14:7: note:   candidate expects 1 argument, 0 provided
include/Node.hpp:14:7: note: candidate: constexpr Node<int>::Node(Node<int>&&)
include/Node.hpp:14:7: note:   candidate expects 1 argument, 0 provided
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:69: error: ambiguous overload for ‘operator=’ (operand types are ‘Node<int>’ and ‘Node<int>*’)
     Edge    (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=ri
                                                                     ^
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:14:7: note: candidate: Node<int>& Node<int>::operator=(const Node<int>&) <near match>
 class Node {
       ^
include/Node.hpp:14:7: note:   conversion of argument 1 would be ill-formed:
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:69: error: invalid user-defined conversion from ‘Node<int>*’ to ‘const Node<int>&’ [-fpermissive]
     Edge    (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=ri
                                                                     ^
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:17:5: note: candidate is: Node<T>::Node(T) [with T = int] <near match>
     Node                    ( T element )           {this->_element=element;}
     ^
include/Node.hpp:17:5: note:   conversion of argument 1 would be ill-formed:
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:69: error: invalid conversion from ‘Node<int>*’ to ‘int’ [-fpermissive]
     Edge    (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=ri
                                                                     ^
include/Edge.hpp:8:69: error: invalid conversion from ‘Node<int>*’ to ‘int’ [-fpermissive]
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:17:5: note:   initializing argument 1 of ‘Node<T>::Node(T) [with T = int]’
     Node                    ( T element )           {this->_element=element;}
     ^
include/Node.hpp:14:7: note: candidate: Node<int>& Node<int>::operator=(Node<int>&&) <near match>
 class Node {
       ^
include/Node.hpp:14:7: note:   conversion of argument 1 would be ill-formed:
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:69: error: invalid user-defined conversion from ‘Node<int>*’ to ‘Node<int>&&’ [-fpermissive]
     Edge    (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=ri
                                                                     ^
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:17:5: note: candidate is: Node<T>::Node(T) [with T = int] <near match>
     Node                    ( T element )           {this->_element=element;}
     ^
include/Node.hpp:17:5: note:   conversion of argument 1 would be ill-formed:
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:69: error: invalid conversion from ‘Node<int>*’ to ‘int’ [-fpermissive]
     Edge    (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=ri
                                                                     ^
include/Edge.hpp:8:69: error: invalid conversion from ‘Node<int>*’ to ‘int’ [-fpermissive]
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:17:5: note:   initializing argument 1 of ‘Node<T>::Node(T) [with T = int]’
     Node                    ( T element )           {this->_element=element;}
     ^
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:69: error: conversion to non-const reference type ‘class Node<int>&&’ from rvalue of type ‘Node<int>’ [-fpermissive]
     Edge    (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=ri
                                                                     ^
include/Edge.hpp:8:95: error: ambiguous overload for ‘operator=’ (operand types are ‘Node<int>’ and ‘Node<int>*’)
     (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=rightNode;
                                                                                       ^
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:14:7: note: candidate: Node<int>& Node<int>::operator=(const Node<int>&) <near match>
 class Node {
       ^
include/Node.hpp:14:7: note:   conversion of argument 1 would be ill-formed:
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:95: error: invalid user-defined conversion from ‘Node<int>*’ to ‘const Node<int>&’ [-fpermissive]
     (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=rightNode;
                                                                                       ^
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:17:5: note: candidate is: Node<T>::Node(T) [with T = int] <near match>
     Node                    ( T element )           {this->_element=element;}
     ^
include/Node.hpp:17:5: note:   conversion of argument 1 would be ill-formed:
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:95: error: invalid conversion from ‘Node<int>*’ to ‘int’ [-fpermissive]
     (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=rightNode;
                                                                                       ^
include/Edge.hpp:8:95: error: invalid conversion from ‘Node<int>*’ to ‘int’ [-fpermissive]
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:17:5: note:   initializing argument 1 of ‘Node<T>::Node(T) [with T = int]’
     Node                    ( T element )           {this->_element=element;}
     ^
include/Node.hpp:14:7: note: candidate: Node<int>& Node<int>::operator=(Node<int>&&) <near match>
 class Node {
       ^
include/Node.hpp:14:7: note:   conversion of argument 1 would be ill-formed:
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:95: error: invalid user-defined conversion from ‘Node<int>*’ to ‘Node<int>&&’ [-fpermissive]
     (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=rightNode;
                                                                                       ^
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:17:5: note: candidate is: Node<T>::Node(T) [with T = int] <near match>
     Node                    ( T element )           {this->_element=element;}
     ^
include/Node.hpp:17:5: note:   conversion of argument 1 would be ill-formed:
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:95: error: invalid conversion from ‘Node<int>*’ to ‘int’ [-fpermissive]
     (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=rightNode;
                                                                                       ^
include/Edge.hpp:8:95: error: invalid conversion from ‘Node<int>*’ to ‘int’ [-fpermissive]
In file included from include/Edge.hpp:2:0,
                 from include/Graph.hpp:1,
                 from src/Main.cpp:2:
include/Node.hpp:17:5: note:   initializing argument 1 of ‘Node<T>::Node(T) [with T = int]’
     Node                    ( T element )           {this->_element=element;}
     ^
In file included from include/Graph.hpp:1:0,
                 from src/Main.cpp:2:
include/Edge.hpp:8:95: error: conversion to non-const reference type ‘class Node<int>&&’ from rvalue of type ‘Node<int>’ [-fpermissive]
     (Node<T> *leftNode, Node<T> *rightNode) {this->_leftNode=leftNode;this->_rightNode=rightNode;
                                                                                       ^
Makefile:19: recipe for target 'default' failed
make: *** [default] Error 1

3 个答案:

答案 0 :(得分:2)

您的成员_leftNode_rightNode需要初始化,但Node没有默认构造函数。您当前的构造函数不会初始化它们,但会尝试在构造函数体中为它们分配新值。

您可以修改Edge构造函数,在其成员初始化列表中初始化它们,如下所示:

Edge(Node<T>& leftNode, Node<T>& rightNode):
     _leftNode(leftNode), _rightNode(rightNode)
{
}    

或者您可以向Node添加默认构造函数 - 一个不带参数。

template <typename T>
class Node {
public:
    Node() = default;
    // ...

此外,您可以对Node( T element )构造函数执行相同的操作,并尽可能使用constNode( const T& element )之类的Edge(const Node<T>& leftNode, const Node<T>& rightNode)引用。

https://godbolt.org/g/R7MS4A

答案 1 :(得分:1)

如果您的用例不需要有关element的信息(例如,编写只需走图而不必访问其节点数据的通用算法),您可以尝试将数据与接口的其余部分分开。这是一般的想法:

#include <iostream>

// Note: don't do this
using namespace std;

将节点元数据拆分为非模板化的类INode

class INode {
public:
    void heuristic(double heuristic) { this->_heuristic = heuristic; }
    void visited(bool visited) { this->_visited = visited; }
    void incrementOrder() { this->_order++; }
    void decrementOrder() { this->_order--; }

    //Getters
    int order() { return this->_order; }
    double heuristic() { return this->_heuristic; }
    bool isVisited() { return this->_visited; }

protected:
    double _heuristic;
    bool _visited;
    int _order;
};

创建模板化包装器以保存数据

template <typename T>
class Node : public INode {
public:
    Node(T element) { this->_element = element; }

    void element(T element) { this->_element = element; }
    T element() { return this->_element; }

protected:
    T _element;
};

如果Edge不需要了解element,则可以使用INode代替。

class Edge {
public:
    //Edge    (Node<T>& leftNode, Node<T>& rightNode) {this->_leftNode=leftNode;this->_rightNode=rightNode;}
    Edge(INode leftNode, INode rightNode)
        : _leftNode(leftNode)
        , _rightNode(rightNode)
    {
    }

    INode leftNode() { return this->_leftNode; }
    INode rightNode() { return this->_rightNode; }

    void leftNode(INode leftNode) { this->_leftNode = leftNode; }
    void rightNode(INode rightNode) { this->_rightNode = rightNode; }

protected:
    INode _leftNode;
    INode _rightNode;
};

您现在可以按如下方式使用它:

int main()
{
    Node<int> l(1);
    Node<int> r(2);
    Edge edge(l, r);
}

请将此视为伪代码以演示该想法 - 即使它编译它也存在对象切片的一些问题。您需要确保拥有虚拟类并使用(const)引用。

答案 2 :(得分:0)

在您使用特定类型对其进行实例化之前,模板化的类不存在。此外,模板Node<int>Node<char>的类型不同。如果希望Edge类能够处理Node而不将Edge类作为模板类本身,则需要在Edge类中明确指定Node类型,如下所示:

Edge(const Node<int>& leftNode, const Node<int>& rightNode) { ... }

或者您必须将Edge类转换为模板,以便能够一般地处理具有不同类型节点的边。