访问说明符不是万无一失的?

时间:2010-12-26 08:55:12

标签: c++ macros encapsulation access-specifier

如果我有这样的课程,

class Sample
{
private:
      int X;
};

然后我们无法从外部访问X,所以这是非法的,

    Sample s;
    s.X = 10; // error - private access

但我们可以在不修改课程的情况下访问!我们需要做的就是这个,

#define private public  //note this define!

class Sample
{
private:
      int X;
};

//outside code
Sample s;
s.X = 10; //no error!

ideone上的工作代码:http://www.ideone.com/FaGpZ

这意味着,我们可以通过在类定义之前或#include <headerfile.h>之前定义此类宏来更改访问说明符,

#define public private //make public private
//or
#define protected private //make protected private
//or
#define so on

这不是C ++的问题(宏/访问说明符/其他)吗?

无论如何,这个主题的重点是:

使用宏,我们很容易违反封装。访问说明符并非万无一失!我是对的吗?

5 个答案:

答案 0 :(得分:7)

首先,这样做是违法的。 private是一个关键字,您不能将其用作宏中的标识符;你的程序将是不正确的。

但无论如何,它根本不是宏的问题。这是傻瓜以愚蠢的方式使用它们。 :)(他们在那里帮助你保持安全,无论你怎么做,他们都不会帮助你安全并阻止他们访问它们.C ++可以防止Murphy,而不是Machiavelli。)

请注意,您可以以格式良好且定义明确的方式访问私有项,如demonstrated here。再一次,这不是语言的问题,只是语言的工作不仅仅是做必要的事情来保持窥探。

答案 1 :(得分:6)

  

但是我们可以在不编辑课程的情况下访问它!我们需要做的就是这个,

从技术上讲,你所展示的只是“我们可以将合法程序变成未定义的行为”,而无需编辑一个特定的类。

这几乎不是新闻。您也可以通过在main()末尾添加这样的行来将其转换为未定义的行为:

int i = 0;
i = ++i;

C ++中的访问说明符不是安全功能它们不能防止黑客攻击,并且它们不会防止人们故意在您的代码中引入错误。

它们只是允许编译器帮助维护某些类不变量。如果您不小心尝试访问私有成员,它们允许编译器通知您,就像它是公共的一样。你所展示的只是“如果我特意试图打破我的计划,我可以”。希望这对任何人来说都应该是一个惊喜。

正如@Gman所说,在C ++语言中重新定义关键字是未定义的行为。它可能似乎适用于您的编译器,但它不再是一个定义良好的C ++程序,编译器原则上可以做任何它喜欢的事情。

答案 2 :(得分:3)

  

但我们可以在不编辑课程的情况下使其无法访问

虽然不是在编辑包含该类的源文件。

是的,宏可以让你在脚下射击。这几乎不是新闻......但这是一个特别令人不安的例子,因为“违反封装”你必须强制类来定义骨头宏本身,或者包含一个这样做的头文件。

换句话说:你能否在真正的,负责任的软件开发中看到这是一个问题?

答案 3 :(得分:0)

@Nawaz,你的帖子很有意思,我以前从没想过这个。但是,我相信你的问题的答案很简单:将C ++(或可能是任何语言)安全性视为组织代码的一种方式,而不是警察。

基本上,由于所有变量都是在您自己的代码中定义的,因此无论您在何处定义它们,都应该能够访问它们。因此,您不应该对找到访问私人会员的方法感到惊讶。

实际上,甚至有一种更简单的方法来访问私有变量。想象一下,你有一个这个类的库:

class VerySecure
{
private:
    int WorldMostSecureCode;
};

让我说我在我的代码中使用你非常安全的类。我可以通过这种方式轻松访问私人会员:

VerySecury a;
int *myhacker = (int*)(&a);
int b = (*myhacker);
printf("Here is your supposed world secret: %d :-) \n", b);

怎么样?!!

答案 4 :(得分:-1)

没有。它将破坏私人方法的破坏。如果编译器能够告诉这些私有方法无法在其他地方访问,那么它们可以被内联和优化,并且它们可能不会出现在目标文件中,因此它们将无法访问。

以此为例。它可以工作,无法链接或无法运行可执行文件,具体取决于您使用的优化/剥离标志以及如何编译事物(即,您可以将实现放在共享库中)

class A {
// i need this one ...
private:
        void stupid_private();
public:
        void unlock(std::string password);
};

实施档案:

#include <iostream>
#include "a.h++"

// uncomment this for more g++ fun
// __attribute__((visibility("hidden")))
void A::stupid_private() {
        std::cout << "let's output something silly." << std::endl;
}
void A::unlock(std::string password) {
        if (password == "jumbo")
                stupid_private();
}

用户文件:

#define private public
#include "a.h++"

int main() {
        A a;
        a.stupid_private();
        return 0;
}