Спецификаторы доступа не являются надежными? - PullRequest
2 голосов
/ 26 декабря 2010

Если у меня есть такой класс,

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 ]

7 голосов
/ 26 декабря 2010

Прежде всего, это незаконно. private - это ключевое слово, и вы не можете использовать его как идентификатор в макросе; ваша программа будет плохо сформирована.

Но в любом случае это не проблема с макросами вообще. Это с дураком, который использовал их глупо. :) (Они здесь, чтобы помочь вам быть в безопасности, они не для того, чтобы помочь вам быть в безопасности и заблокировать любой доступ к ним, что бы вы ни пытались. C ++ защищает от Мерфи, а не Макиавелли.)

Обратите внимание, что вы можете получить доступ к рядовым лицам в правильной и четкой форме, как показано здесь . Опять же, это не проблема с языком, просто работа языка не в том, чтобы делать больше, чем нужно, чтобы не поддаваться на руки.

6 голосов
/ 26 декабря 2010

Но мы можем сделать его доступным без редактирования класса! Все, что нам нужно сделать, это,

Технически, все, что вы показали, это то, что «мы можем превратить легальную программу в неопределенное поведение», не редактируя один конкретный класс.

Это вряд ли новость. Вы также можете превратить его в неопределенное поведение, просто добавив такую ​​строку в конец main():

int i = 0;
i = ++i;

Спецификаторы доступа в C ++ не являются функцией безопасности. Они не защищают от попыток взлома и не защищают от людей, преднамеренно пытающихся внести ошибки в ваш код.

Они просто позволяют компилятору помочь поддерживать определенные инварианты классов. Они позволяют компилятору сообщать вам, если вы случайно попытаетесь получить доступ к приватному члену, как если бы он был публичным. Все, что вы показали, это то, что «если я специально попытаюсь сломать свою программу, я смогу». Надеюсь, это никого не должно удивлять.

Как сказал @Gman, переопределение ключевых слов в языке C ++ - это неопределенное поведение . Может показаться, что он работает на вашем компиляторе, но он больше не является четко определенной программой на C ++, и компилятор может в принципе делать все, что ему нравится.

3 голосов
/ 26 декабря 2010

Но мы можем сделать его доступным без редактирования класса

Не без редактирования исходного файла, содержащего класс.

Да, макросы позволяют снимать себя вступня.Это вряд ли новость ... но это особенно беспокоящий пример, так как для "нарушения инкапсуляции" вы должны заставить класс либо определить сам макрос с костяными головами, либо включить заголовочный файл, который это делает.

Другими словами: видите ли вы проблему в real , ответственной разработке программного обеспечения?

0 голосов
/ 26 декабря 2010

@ Наваз, ваш пост интересный, я никогда не думал об этом раньше. Однако я считаю, что ответ на ваш вопрос прост: думайте о безопасности 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);

Как это? !!

0 голосов
/ 26 декабря 2010

Нет.это разрушит частные методы.если компилятор может сказать, что к этим закрытым методам нельзя получить доступ в другом месте, то они могут быть встроенными и оптимизированными, и они могут не появиться в объектном файле, поэтому они будут недоступны.

Возьмите этоВ качестве примера.Он либо работает, либо не может связать, либо не может запустить исполняемый файл, в зависимости от используемых вами флагов оптимизации / извлечения и того, как вы его скомпилировали (т. Е. Вы можете поместить реализацию в разделяемую библиотеку или нет)

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;
}
...