安全/正确使用指针

时间:2016-04-01 16:14:32

标签: c++ pointers reference encapsulation

我知道您不应该返回指向成员数据的指针或引用,因为它会破坏封装。但我不确定这是不是在这种情况下发生了什么,我可以使用一些澄清......

树标题 -

#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是一个指针,我取消引用它并返回对它所指向的内容的引用,那么我不打破封装正确吗?

4 个答案:

答案 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),打破封装。