这两个类是否违反了封装?

时间:2010-01-19 15:46:21

标签: c++ inheritance encapsulation

class X
{
protected:
    void protectedFunction() { cout << "I am protected" ; }
};

class Y : public X
{
public:
    using X::protectedFunction;
};

int main()
{
    Y y1;
    y1.protectedFunction();
}

这样我就可以公开基类的一个函数。

  1. 这是否违反了封装原则?
  2. 是否有一个特定的原因,为什么这是标准的?
  3. 是否有任何用途,或者是否会在新标准中更改?
  4. 标准中是否有与此相关的未解决问题?

10 个答案:

答案 0 :(得分:18)

你自己做了。
你可以写

class Y : public X
{
public:
    void doA()
    {
       protectedFunction();
    }
};

int main()
{
    Y y1;
    y1.doA(); 
}

我认为没有理由担心它 受保护的函数是继承树中可重用逻辑的一部分。你可以隐藏它们,如果有一些内部逻辑或限制,或者像你的情况那样可以暴露它,如果你确定这不会伤害任何人。

答案 1 :(得分:12)

是的,这就是为什么受保护已经受到了公平的批评。

C ++的创建者Bjarne Stroustrup在他出色的着作“C ++的设计与演变”中对此表示遗憾:

  

我对受保护的担忧之一是   确切地说它太容易了   以一种可能的方式使用共同的基础   懒散地使用了全球数据....   回想起来,我认为受保护的是   一个“好的论据”和   时尚克服了我更好的判断力   和我接受的经验法则   新功能。

答案 2 :(得分:11)

我认为正是Stroustrup本人说C ++中内置的封装和数据完整性功能旨在让诚实的人保持诚实,而不是阻止犯罪分子。

答案 3 :(得分:3)

没有。 protectedFunction()受保护。您可以从派生类中自由调用它,因此您可以直接从Y的公共成员调用它,并从main()调用此公共成员。

如果您可以使用私有方法完成此操作,则会出现问题... (编辑有点清楚)。

答案 4 :(得分:2)

从语言的角度来看,这并不比在派生对象中创建委托方法更违反封装:

class Y : public X
{
public:
    void protectedFunction() {
       X::protectedFunction();
    }
};

一旦方法受到保护,就会根据需要将它提供给派生类。 using声明的意图不是改变继承的方法访问,而是避免方法隐藏的问题(如果不同的重载是X中的公共方法隐藏在类型Y中定义)。

现在,由于语言规则,它可用于更改“已使用”方法的访问级别,如您的示例所示,但这并未真正打开系统中的任何漏洞。最后,派生类不能做任何比以前更多的事情。

如果实际问题是从设计的角度来看特定用法是否违反了封装(这里的设计是应用程序设计,而不是语言设计),那么很可能是肯定的。与公开内部数据或方法的方式完全相同。如果它被设计为受X的初始设计者保护,那么Y实现者​​可能不希望它被公开......(或为同一目的提供委托方法)< / p>

答案 5 :(得分:2)

没有。

要使用公共方法,您应该拥有Y的实例,这将不起作用:

int main()
{
    X y1;
    y1.protectedFunction();
}

如果新定义中的Y暴露了一个新接口,它就是Y.X仍然受到保护。

答案 6 :(得分:2)

在C ++中,即使是私有修饰符也不能保证封装。没有人可以阻止你在脚下射击自己。

Herb Sutter在他的文章“Uses and Abuses of Access Rights”中阐述了如何“打破封装”的不同方式。

这是赫伯文章中的有趣例子。

邪恶的宏魔法

#define protected public // illegal
#include "X.h"
//...
X y1;
y1.protectedFunction();

答案 7 :(得分:1)

类设计者应该知道声明一个成员函数或变量(尽管所有变量应该是私有的,真的)作为受保护的大多数与声明它是公开的(因为你展示它很容易获得受保护的东西)。 考虑到这一点,在基类中实现这些功能时应注意考虑“意外”使用。这不是对封装的违反,因为您可以访问它并公开它。

受保护只是宣传公开事物的一种更复杂的方式!

答案 8 :(得分:1)

不,我真的没有看到问题。

而不是using,你可以这样做:

class X
{
protected:
    void protectedFunction() { cout << "i am protected" ; }
};

class Y : public X
{
public:
    void protectedFunction() { X::protectedFunction(); }
};

任何类都可以接受任何可见的成员,并决定公开公开它。这样做可能是糟糕的课堂设计,但它肯定不是语言中的缺陷。私有或受保护成员的整个要点是,类本身必须决定谁应该访问该成员。如果班级决定“我将给全世界访问”,那么这就是班级的设计方式。

如果我们遵循您的逻辑,那么getter和setter也会违反封装。有时它们会这样做。但不是因为语言被打破了。仅仅因为你选择设计破碎的课程。

通过使成员受到保护,您可以为派生类提供与成员一起任何他们喜欢的自由。他们可以看到它,因此他们可以修改它,或公开公开它。当您保护成员时,您选择使这成为可能。如果你不想那样,你应该把它变成私有的。

答案 9 :(得分:1)

我个人认为这个问题应该作为设计问题而不是技术问题来回答。

我会问,“首先,受保护的方法有什么意义?”它是一个只有子类应该调用的方法,还是一个子类应该覆盖的方法?但是,它可能是一种在通用基类中不期望的方法,但可能在子类中预期。对于基类的客户端,他们从未知道该受保护的方法。子类的创建者选择扩展合同,现在受保护的方法是公开的。问题确实不应该是C ++允许的,但它适合你的课程,合同和未来的维护者。当然它可能是一种难闻的气味,但实际上你需要使它适用于所涉及的用例。

如果您确实将受保护的方法设为公开,请确保为维护人员正确提供内部文档,说明为何做出此特定决策的理由。

一般来说,为了安全起见,作为前面提到的贡献者,您可能希望在子类中使用委托函数(具有不同的名称)。因此,不是“get(int)”而是“getAtIndex(int)”或其他东西。这使您可以更轻松地重构/保护/抽象/记录该文件。

相关问题