Подтвердить что ты не робот

С++ Является ли частное частным?

Я тестировал действительность спецификатора доступа private в С++. Здесь:

Интерфейс:

// class_A.h

class A
{
public:
    void printX();
private:
    void actualPrintX();
    int x;
};

Реализация:

// class_A.cpp
void A::printX()
{
    actualPrintX();
}

void A::actualPrintX()
{
    std::cout << x:
}

Я построил это в статической библиотеке (.a/.lib). Теперь мы имеем пару class_A.h и classA.a(или classA.lib). Я отредактировал class_A.h и удалил из него private:.

Теперь в другом классеTester.cpp:

#include "class_A.h"    // the newly edited header

int main()
{
    A a;

    a.x = 12;           // both G++ and VC++ allowed this!
    a.printX();         // allowed, as expected
    a.actualPrintX();   // allowed by G++, VC++ gave a unresolved linker error

    return 0;
}

Я знаю, что после вмешательства в заголовок библиотеки все ставки отключены (я имею в виду, системная целостность и т.д.). Хотя метод хакерский, это действительно разрешено? Есть ли способ заблокировать это? Или я здесь что-то не так?

4b9b3361

Ответ 1

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

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

Ответ 2

Вы отклонились от того, что разрешено на С++, поэтому то, что вы делаете, недопустимо, но, конечно, в некоторых ситуациях оно может работать с некоторыми компиляторами.

В частности, вы нарушаете правило определения 1.

Эта статья статьи от Herb Sutter объясняет это довольно хорошо - она ​​также предоставляет законный и переносимый способ обхода системы спецификатора доступа.

Ответ 3

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

Ответ 4

Я пробовал. Это nm программы, которую я написал, имея тест класса с одним личным методом и общедоступным.

0000000100000dcc T __ZN4Test3barEv
0000000100000daa T __ZN4Test3fooEv

Как вы можете видеть, подпись точно такая же. У компоновщика нет абсолютно ничего, чтобы отличать частный метод от публичного.

Ответ 5

Я согласен с большинством других ответов.

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

Ответ 6

Нет реализации A:: actualPrintX в любом месте. Это ваша ошибка компоновщика.

Ответ 7

Поскольку никто не упомянул способ блокировать это... Один из возможных способов блокировки доступа к закрытым членам - объявить их как отдельный внутренний тип, невидимый вне файла. Конечно, если вы хотите предоставить явный доступ к этому внутреннему, вам необходимо будет предоставить внутреннюю декларацию. Это также обычно делается с использованием внутреннего заголовка, содержащего этот тип.

Примечание. Вам нужно будет отслеживать выделение/освобождение этого внутреннего объекта в этом примере. Есть и другие способы сделать это, чтобы этого не требовалось.

// class_A.h
class A {
public:
  void printX();
private:
  void *Private;
};

// class_A.cpp
class A_private {
  void actualPrintX();
  int x;
};

void A::printX() {
  reinterpret_cast<A_private *>(Private)->actualPrintX();
}

void A_private::actualPrintX() {
  std::cout << x:
}

Ответ 8

В большинстве случаев вам даже не нужно редактировать заголовочный файл, чтобы публиковать публичные члены. Вы можете сделать это с помощью препроцессора. Что-то вроде этого:

//"classWithPrivateMembers.hpp"
class C
{
private: //this is crucial for this method to work
    static int m;
};

int C::m = 12;

и тогда это будет работать:

#define private public  
#include "classWithPrivateMembers.hpp"  
#undef private

int main()
{
    C::m = 34; // it works!
}

Ответ 9

Помните также, что при изменении доступа к переменной-члену компилятор может поместить его в другое смещение внутри объекта класса. Стандарт позволяет компиляторам довольно много свободы в перегруппировке членов (по крайней мере, на том же уровне доступа, я думаю).