我知道您不应该返回指向成员数据的指针或引用,因为它会破坏封装。但我不确定这是不是在这种情况下发生了什么,我可以使用一些澄清......
树标题 -
#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是一个指针,我取消引用它并返回对它所指向的内容的引用,那么我不打破封装正确吗?
答案 0 :(得分:2)
打破封装没有问题。没有任何。问题在于打破不变。封装是一个神话。不变是一件真实的事。
此处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!
问题是,这个数据是不变的值得保护吗?我不知道,只有你能说出来。
答案 1 :(得分:1)
你不会破坏封装,只需用户可以自己做TreeNode *my_node = new TreeNode;
用户只能调用TreeNode的公共方法,并且因为你返回{{1参考,他甚至不能调用会改变事物的方法。
所以我不认为这是一个问题。相比之下,这个是可能存在问题的代码:
const
通过返回对成员变量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;
} ;
的引用,允许用户在不实际移动伺服的情况下弄乱您的状态。这可能会使程序失去同步并引起悲伤。
答案 2 :(得分:1)
我不认为这与指针有任何关系。我会说你打破了封装,因为TreeNode
对象应该是一个实现细节,理想情况下公共接口应该只处理用于存储的TreeNode
个对象。
我假设你的Tree
被用来存储一些非结构数据?
然后封装应理想地隐藏来自不是元素的公共API
或迭代器到非结构数据元素的所有内容。想想STL
容器。您不需要查看std::list
使用的链接列表的根指针,因为它是隐藏的实现细节。但是做可以使用std::list::front()
查看非结构数据的第一个元素。
答案 3 :(得分:0)
我认为你打破了封装,因为如果某些代码调用getRootNode()
,它可以更改rootNodeOfExpressionTree
指向的数据,而无需通过类(甚至rootNodeOfExpressionTree
),打破封装。