Safe/Correct 指针的使用
Safe/Correct use of pointers
我知道您不应该 return 指向成员数据的指针或引用,因为它会破坏封装。但我不确定在这种情况下是否发生了这种情况,我可以使用一些说明...
树头-
#include "TreeNode.h"
class Tree
{
public:
explicit Tree(Tree* treeToCopy);
explicit Tree(TreeNode*);
TreeNode& getRootNode() const;
private:
TreeNode* rootNodeOfExpressionTree;
};
Tree.cpp-
#include "Tree.h"
Tree::Tree(Tree* treeToCopy)
{
rootNodeOfExpressionTree = &treeToCopy->getRootNode();
}
Tree::Tree(TreeNode* rootNodeOfExpressionTree)
:rootNodeOfExpressionTree(rootNodeOfExpressionTree)
{
}//empty constructor body
TreeNode& Tree::getRootNode() const
{
return *rootNodeOfExpressionTree;
}
我的问题是关于 getRootNode() 方法的。由于 rootNodeOfExpressionTree 是一个指针,我正在取消引用它并 returning 引用它指向的任何内容,那么我没有破坏封装正确吗?
我认为你正在破坏封装,因为如果某些代码调用 getRootNode()
,它可以更改数据 rootNodeOfExpressionTree
指向而无需通过 class(甚至 rootNodeOfExpressionTree
),这会破坏封装。
你并没有破坏封装,就像用户可以自己做一样 TreeNode *my_node = new TreeNode;
用户只能调用 TreeNode 的 public 方法,因为你返回一个 const
参考,他甚至不能调用会改变事物的方法。
所以我认为这不是问题。相比之下,this 是可能有问题的代码:
class ServoController {
void setPosition( int x ) { /* do some stuff to move servo, then */ current_position = x; }
int &getPosition( void ) { return current_position; } // <--- don't do this!
// ...
int current_position;
} ;
通过返回对成员变量 current_position
的引用,您允许用户在不实际移动舵机的情况下扰乱您的状态。这可能会使程序不同步并引起麻烦。
我不认为这与指针有任何关系。我会说你正在破坏封装,因为 TreeNode
对象应该是一个实现细节,而 public 接口理想情况下应该只处理 TreeNode
对象用于存储的内容。
我假设你的 Tree
被用来存储一些非结构数据?
然后 encapsulation 理想情况下应该隐藏 public API
中不是元素的所有内容,或者是 [=23 的元素的迭代器=]非结构性 数据。想想 STL
个容器。您不需要查看 std::list
使用的 链表 的 根指针 ,因为它隐藏了实现细节。但是您确实看到非结构数据的第一个元素 std::list::front()
。
打破封装没有问题。 None 随便。问题在于打破 不变性 。封装是一个神话。不变量是真实存在的。
此处 getRootNode
的调用者可以访问 Tree
成员指向的数据。这意味着调用者无法更改指针本身,但可以更改指针指向的数据。我意识到这可能令人困惑,所以这里有一个简单的例子:
struct A {
A() : member(new int(42)) {}
int& get() const { return *member; }
private:
int* member;
};
....
A a; // *a.member is 42
int& x = a.get();
x = 56; // *a.member is 56!
问题是,此数据是否不变量值得保护?我不知道,只有你知道。
我知道您不应该 return 指向成员数据的指针或引用,因为它会破坏封装。但我不确定在这种情况下是否发生了这种情况,我可以使用一些说明...
树头-
#include "TreeNode.h"
class Tree
{
public:
explicit Tree(Tree* treeToCopy);
explicit Tree(TreeNode*);
TreeNode& getRootNode() const;
private:
TreeNode* rootNodeOfExpressionTree;
};
Tree.cpp-
#include "Tree.h"
Tree::Tree(Tree* treeToCopy)
{
rootNodeOfExpressionTree = &treeToCopy->getRootNode();
}
Tree::Tree(TreeNode* rootNodeOfExpressionTree)
:rootNodeOfExpressionTree(rootNodeOfExpressionTree)
{
}//empty constructor body
TreeNode& Tree::getRootNode() const
{
return *rootNodeOfExpressionTree;
}
我的问题是关于 getRootNode() 方法的。由于 rootNodeOfExpressionTree 是一个指针,我正在取消引用它并 returning 引用它指向的任何内容,那么我没有破坏封装正确吗?
我认为你正在破坏封装,因为如果某些代码调用 getRootNode()
,它可以更改数据 rootNodeOfExpressionTree
指向而无需通过 class(甚至 rootNodeOfExpressionTree
),这会破坏封装。
你并没有破坏封装,就像用户可以自己做一样 TreeNode *my_node = new TreeNode;
用户只能调用 TreeNode 的 public 方法,因为你返回一个 const
参考,他甚至不能调用会改变事物的方法。
所以我认为这不是问题。相比之下,this 是可能有问题的代码:
class ServoController {
void setPosition( int x ) { /* do some stuff to move servo, then */ current_position = x; }
int &getPosition( void ) { return current_position; } // <--- don't do this!
// ...
int current_position;
} ;
通过返回对成员变量 current_position
的引用,您允许用户在不实际移动舵机的情况下扰乱您的状态。这可能会使程序不同步并引起麻烦。
我不认为这与指针有任何关系。我会说你正在破坏封装,因为 TreeNode
对象应该是一个实现细节,而 public 接口理想情况下应该只处理 TreeNode
对象用于存储的内容。
我假设你的 Tree
被用来存储一些非结构数据?
然后 encapsulation 理想情况下应该隐藏 public API
中不是元素的所有内容,或者是 [=23 的元素的迭代器=]非结构性 数据。想想 STL
个容器。您不需要查看 std::list
使用的 链表 的 根指针 ,因为它隐藏了实现细节。但是您确实看到非结构数据的第一个元素 std::list::front()
。
打破封装没有问题。 None 随便。问题在于打破 不变性 。封装是一个神话。不变量是真实存在的。
此处 getRootNode
的调用者可以访问 Tree
成员指向的数据。这意味着调用者无法更改指针本身,但可以更改指针指向的数据。我意识到这可能令人困惑,所以这里有一个简单的例子:
struct A {
A() : member(new int(42)) {}
int& get() const { return *member; }
private:
int* member;
};
....
A a; // *a.member is 42
int& x = a.get();
x = 56; // *a.member is 56!
问题是,此数据是否不变量值得保护?我不知道,只有你知道。