什么时候 public/private 的排序不是样式选择?
When is the ordering of public/private not a style choice?
所以通常我遵循将我的 public 成员函数放在我的私有属性之前的惯例,比如
class SomeClass {
public:
void amazingMethod();
private:
int fantasticAttribute;
};
因为用户(包括我)首先希望在 class 中看到的是我可以使用的东西。然而,我最近的一个项目引入了一些真正的怪异。
template<typename T>
class LinkedList {
public:
class LinkedListIterator {
public:
LinkedListIterator(Node* node) : node(node) {}
LinkedListIterator& operator++() {
if (node != nullptr) {
node = node->next;
}
}
private:
Node* node;
};
LinkedListIterator begin() {
return LinkedListIterator(head);
}
private:
struct Node {
Node* next;
};
Node* head;
};
此代码 在 Visual Studio 2015 年无法编译 ,报告当 LinkedListIterator
尝试使用它时未定义 Node
。但奇怪的是,如果我翻转 LinkedList
所以它被声明为
template <typename T>
class LinkedList {
private:
//everything that was in private before
public:
//everything that was in public before
};
一切都正确编译!这只是一个 Visual Studio 怪癖吗?我猜这与它是一个模板这一事实有关 class 但我不知道。
我怎么知道什么时候我必须泪流满面地放弃首先宣布 public 成员(正如大多数惯例所建议的那样)?什么时候它不仅仅是一种风格选择?
它与 public 和 private 本身无关。它与Node
在使用时是否已经定义有关。
与访问类型无关。它与 LinkListIterator
试图使用编译器尚未发现的类型有关。
但是,由于迭代器 class 仅使用指向 Node
类型的指针,因此前向声明就足够了。下面的代码添加了前向声明并编译得很好:
template<typename T>
class LinkedList {
private:
struct Node; // Private forward declaration of the private class
public:
class LinkedListIterator {
public:
LinkedListIterator(Node* node) : node(node) {}
LinkedListIterator& operator++() {
if (node != nullptr) {
node = node->next;
}
}
private:
Node* node;
};
LinkedListIterator begin() {
return LinkedListIterator(head);
}
private:
struct Node {
Node* next;
};
Node* head;
};
int main()
{
return 0;
}
如果您想先声明 public 成员,请重写您的定义:
template<typename T>
class LinkedList {
public:
class LinkedListIterator;
LinkedListIterator begin();
private:
struct Node;
Node* head;
};
template<typename T>
struct LinkedList<T>::Node {
Node* next;
};
template<typename T>
class LinkedList<T>::LinkedListIterator {
public:
LinkedListIterator(Node* node);
LinkedListIterator& operator++();
private:
Node* node;
};
template<typename T>
LinkedList<T>::LinkedListIterator::LinkedListIterator(Node* node) : node(node) {}
template<typename T>
typename LinkedList<T>::LinkedListIterator& LinkedList<T>::LinkedListIterator::operator++() {
if (node != nullptr) {
node = node->next;
}
return *this;
}
template<typename T>
typename LinkedList<T>::LinkedListIterator LinkedList<T>::begin() {
return LinkedListIterator(head);
}
所以通常我遵循将我的 public 成员函数放在我的私有属性之前的惯例,比如
class SomeClass {
public:
void amazingMethod();
private:
int fantasticAttribute;
};
因为用户(包括我)首先希望在 class 中看到的是我可以使用的东西。然而,我最近的一个项目引入了一些真正的怪异。
template<typename T>
class LinkedList {
public:
class LinkedListIterator {
public:
LinkedListIterator(Node* node) : node(node) {}
LinkedListIterator& operator++() {
if (node != nullptr) {
node = node->next;
}
}
private:
Node* node;
};
LinkedListIterator begin() {
return LinkedListIterator(head);
}
private:
struct Node {
Node* next;
};
Node* head;
};
此代码 在 Visual Studio 2015 年无法编译 ,报告当 LinkedListIterator
尝试使用它时未定义 Node
。但奇怪的是,如果我翻转 LinkedList
所以它被声明为
template <typename T>
class LinkedList {
private:
//everything that was in private before
public:
//everything that was in public before
};
一切都正确编译!这只是一个 Visual Studio 怪癖吗?我猜这与它是一个模板这一事实有关 class 但我不知道。
我怎么知道什么时候我必须泪流满面地放弃首先宣布 public 成员(正如大多数惯例所建议的那样)?什么时候它不仅仅是一种风格选择?
它与 public 和 private 本身无关。它与Node
在使用时是否已经定义有关。
与访问类型无关。它与 LinkListIterator
试图使用编译器尚未发现的类型有关。
但是,由于迭代器 class 仅使用指向 Node
类型的指针,因此前向声明就足够了。下面的代码添加了前向声明并编译得很好:
template<typename T>
class LinkedList {
private:
struct Node; // Private forward declaration of the private class
public:
class LinkedListIterator {
public:
LinkedListIterator(Node* node) : node(node) {}
LinkedListIterator& operator++() {
if (node != nullptr) {
node = node->next;
}
}
private:
Node* node;
};
LinkedListIterator begin() {
return LinkedListIterator(head);
}
private:
struct Node {
Node* next;
};
Node* head;
};
int main()
{
return 0;
}
如果您想先声明 public 成员,请重写您的定义:
template<typename T>
class LinkedList {
public:
class LinkedListIterator;
LinkedListIterator begin();
private:
struct Node;
Node* head;
};
template<typename T>
struct LinkedList<T>::Node {
Node* next;
};
template<typename T>
class LinkedList<T>::LinkedListIterator {
public:
LinkedListIterator(Node* node);
LinkedListIterator& operator++();
private:
Node* node;
};
template<typename T>
LinkedList<T>::LinkedListIterator::LinkedListIterator(Node* node) : node(node) {}
template<typename T>
typename LinkedList<T>::LinkedListIterator& LinkedList<T>::LinkedListIterator::operator++() {
if (node != nullptr) {
node = node->next;
}
return *this;
}
template<typename T>
typename LinkedList<T>::LinkedListIterator LinkedList<T>::begin() {
return LinkedListIterator(head);
}