C++ частный действительно частный?

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

Интерфейс:

// 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: от него.

Теперь в другом classTester.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;
}

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

18
задан legends2k 16 February 2010 в 13:21
поделиться

9 ответов

В PostgreSQL есть предложение RETURNING

См.: http://www.postgresql.org/docs/8.3/interactive/sql-update.html

-121--5044367-

Я предполагаю, что это не имеет ничего общего с WPF, это вопрос серебристого света.

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

Необходимо создать новый тип с этим событием, а затем создать присоединенное свойство этого типа.

Вот базовый тип, который просто имеет событие: -

public class MyEventer
{
    public event EventHandler MyEvent;

    // What would call this??
    protected void OnMyEvent(EventArgs e)
    {
      if (MyEvent != null)
         MyEvent(this, e);
    }
}

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

public static class MyProps
{

  public static MyEventer GetEventer(DependencyObject obj)
  {
     return (MyEventer)obj.GetValue(EventerProperty );
  }

  public static void SetEventer(DependencyObject obj, MyEventer value)
  {
    obj.SetValue(EventerProperty , value);
  }

  public static readonly DependencyProperty EventerProperty =
        DepencencyProperty.RegisterAttached("Eventer", typeof(MyEventer), typeof(MyProps), null)

  }
}

Теперь вы присоединяете его к элементу управления следующим образом: -

<Border ...>
   <custom:MyProps.Eventer>
      <custom:MyEventer MyEvent="someHandler" />
   </custom:MyProps.Eventer>
</Border>

Если вы скомпилируете проект перед написанием этого файла xaml, вы заметите, что Visual Studio предложит вам возможность создать обработчик событий в коде.

Конечно, это все еще оставляет важный вопрос: Как вы намеревались вызвать событие?

-121--4998119-

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

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

30
ответ дан 30 November 2019 в 05:59
поделиться

В PostgreSQL есть предложение RETURNING

См.: http://www.postgresql.org/docs/8.3/interactive/sql-update.html

-121--5044367-

Я предполагаю, что это не имеет ничего общего с WPF, это вопрос серебристого света.

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

Необходимо создать новый тип с этим событием, а затем создать присоединенное свойство этого типа.

Вот базовый тип, который просто имеет событие: -

public class MyEventer
{
    public event EventHandler MyEvent;

    // What would call this??
    protected void OnMyEvent(EventArgs e)
    {
      if (MyEvent != null)
         MyEvent(this, e);
    }
}

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

public static class MyProps
{

  public static MyEventer GetEventer(DependencyObject obj)
  {
     return (MyEventer)obj.GetValue(EventerProperty );
  }

  public static void SetEventer(DependencyObject obj, MyEventer value)
  {
    obj.SetValue(EventerProperty , value);
  }

  public static readonly DependencyProperty EventerProperty =
        DepencencyProperty.RegisterAttached("Eventer", typeof(MyEventer), typeof(MyProps), null)

  }
}

Теперь вы присоединяете его к элементу управления следующим образом: -

<Border ...>
   <custom:MyProps.Eventer>
      <custom:MyEventer MyEvent="someHandler" />
   </custom:MyProps.Eventer>
</Border>

Если вы скомпилируете проект перед написанием этого файла xaml, вы заметите, что Visual Studio предложит вам возможность создать обработчик событий в коде.

Конечно, это все еще оставляет важный вопрос: Как вы намеревались вызвать событие?

-121--4998119-

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

7
ответ дан 30 November 2019 в 05:59
поделиться

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

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

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

9
ответ дан 30 November 2019 в 05:59
поделиться

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

0000000100000dcc T __ZN4Test3barEv
0000000100000daa T __ZN4Test3fooEv

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

5
ответ дан 30 November 2019 в 05:59
поделиться

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

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

// 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:
}
2
ответ дан 30 November 2019 в 05:59
поделиться

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

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

5
ответ дан 30 November 2019 в 05:59
поделиться

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

//"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!
}
1
ответ дан 30 November 2019 в 05:59
поделиться

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

1
ответ дан 30 November 2019 в 05:59
поделиться

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

2
ответ дан 30 November 2019 в 05:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: