假设我有List和Node的以下定义:
template <class T>
class List {
public:
class Iterator;
class ConstIterator;
//Constructors and Destructors.
List() : head(NULL), tail(NULL), size(0) {}
List(const List& list);
~List();
//Methods
Iterator begin();
ConstIterator begin() const;
Iterator end();
ConstIterator end() const;
void insert(const T& data);
void insert(const T& data, const Iterator& iterator);
void remove(const Iterator& iterator);
int getSize() const;
Iterator find(const T& item);
ConstIterator find(const T& item) const;
void sort();
//Operators
List operator = (const List& list);
private:
class Node;
Node* head;
Node* tail;
int size;
};
template <class T>
class List<T>::Node
{
public:
//Constructors and destructors
Node(const T& _data, const Node* _next) : data(_data), next(_next) {}
~Node(); //Destructor
//Methods
//Operators
Node operator = (const Node& node);
private:
T data;
Node* next;
};
我正在编写一个函数来将数据插入到这样的列表中:
template<class T>
void List<T>::insert(const T& data)
{
Node newNode = new Node(data, NULL);
if (head == NULL)
{
head = &newNode;
tail = &newNode;
}
else
{
(*tail)->next = &newNode;
tail = &newNode;
}
size++;
}
然而,我发现奇怪的是,如果我将(*tail)->next = &newNode;
交换为(*tail).next = &newNode;
,它仍会编译。为什么,这样做的正确方法是什么?
答案 0 :(得分:1)
您的类的定义可以(为了本问题的目的)简化为:
class List {
...
private:
Node* head;
Node* tail;
};
class Node {
...
private:
Node* next;
};
现在使用List::insert
方法:
Node newNode = new Node(data, NULL);
(*tail)->next = &newNode;
...当你使用new
表达式时,结果将是指向新分配的内存的指针
你应该做的是:
Node* newNode = new Node(data, NULL);
tail->next = newNode; // <-- equivalent to (*tail).next = newNode;
答案 1 :(得分:0)
- &gt;运算符将自动为您指向一个指针,然后向右调用该方法。所以:
tail->next
也可以,但
tail.next
不会因为tail是一个指针。要使用。运算符你必须首先在
中去除指针(*tail).next
(*tail)
将指针变为对象。那时你可以使用 - &gt;要么 。
A。不会对指针起作用但是 - &gt;将
一般来说,为了便于打字,我使用了 - &gt;因为它比使用(*)将指针转换为对象更短,所以我可以使用点,但它们是等效的操作。
答案 2 :(得分:0)
使用Node-&gt; tail是写入的简短形式(* Node).tail。两种形式都有效。 Strangeus是你说(* Node) - &gt;尾部编译的事实。为此,必须将Node定义为双指针,即:
Node **tail;
但是你的代码还有其他一些错误。在这一行中:
Node newNode = new Node(data, NULL);
您定义了一个本地对象并为其分配动态内存。正确的方法是:
Node *newNode = new Node(data, NULL); // defining it as a pointer
而不是作为:
head = &newNode;
做的:
head = newNode;
作为最后一点,请考虑使用智能指针而不是原始指针。前者比上一个更安全
答案 3 :(得分:0)
您已注意到(*tail)->next = &newNode
和(*tail).next = &newNode
都编译,这会让您感到奇怪。
但不知何故,你可能也注意到这条线也会编译!
Node newNode = new Node(data, NULL);
是你应该暂停的事情。
你在这里的模板里面。很多东西“编译”。
您是否尝试过实例化模板?
附录:
这里只是为了告诉你有多疯狂,看一下这个程序:
#include <iostream>
using namespace std;
template <class T>
class C {
void f();
};
template <class T>
void C<T>::f() {
int x = new int;
}
int main() {
std::cout << "Hello, world\n";
}
现在看看这个:
$ g++ template-example.cpp && ./a.out
Hello, world
但现在注意
#include <iostream>
using namespace std;
int main() {
int x = new int;
std::cout << "Hello, world\n";
}
产生:
$ g++ hello.cpp
hello.cpp: In function ‘int main()’:
hello.cpp:4: error: invalid conversion from ‘int*’ to ‘int’
TL; DR:当你在某个模板中时,那些不应该编写“DO”的东西!(他们并没有真正编译 - 是的!)