Я могу преобразовать объект и получить доступ к частным элементам данных в C++?

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

7
задан pnuts 20 November 2015 в 23:07
поделиться

6 ответов

I am assuming that

  1. You've already been through "breaking encapsulation is bad" stage,
  2. Exhausted other possible solutions,
  3. Can't change class' header.

There are a few ways to subvert access to a class's private members, as demonstrated in GotW #76.

  1. Duplicate a class definition and add a friend declaration.
  2. Use evil macros: #define private public before including class' header.
  3. Write a class definition with identical binary layout and use reinterpret_cast to switch from original class to a fake one.
  4. Specialize a template member function if there is one (the only portable solution).
18
ответ дан 6 December 2019 в 07:07
поделиться

With the idea you suggest in your question, you don't need to copy the original object. If you write your own "all public" variation of the real class declaration, then cast a pointer to that new type, you can directly access the object through it.

The reason why none of this is a good idea is simple. You must be manipulating objects of a class of which you don't control the source (otherwise you'd be able to modify the source to give you the access you need). But if you don't control the source, then what if the maintainers change the layout of their class? Your duplicated version will no longer match up, and there will be no way for the compiler to detect this mismatch. The result will probably be memory corruption at runtime.

3
ответ дан 6 December 2019 в 07:07
поделиться

You can, but you shouldn't. The objects are just memory. You can certainly cast the pointer into an equivalent class that has the same members but where everything is public. But why do you want to do this? Do you have somebody else's code that you need to work with? Get them to add proper accessor methods. Do you really need to treat them as public members? Change the class.

I'm not really sure what you are trying to do, but it's probably a mistake.

1
ответ дан 6 December 2019 в 07:07
поделиться

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

#include <class.h>
ObjectFoo instance;

Это возможно (но опасно, если вы не будете осторожны) измените заголовок (a) или скопируйте заголовок в другое место и включите этот заголовок (b), без перекомпиляции самого класса .

#include <class_fixed.h>
ObjectFoo instance;

Ваш код, в который вы включили новый заголовок, просто подумает , что в объектном файле (который вы не перекомпилировали!) Он найдет реализацию класса, объявленного как в class_fixed. h . Пока сохраняется класс, объявленный как в class.h . Если вы измените смещения элементов (например, добавите новые элементы) в своем новом заголовке, вы мертвы, и код не будет работать должным образом. Но просто изменение доступа работает нормально. Скомпилированный код не знает о доступе, это имеет значение только при компиляции странно.

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


Есть несколько решений.

  1. memcpy ()
    Не надо! Не используйте memcpy, поскольку при копировании объектов иногда применяется особая политика, установленная конструктором классов. Например, auto_ptr s нельзя просто скопировать в память: если вы скопируете в память auto_ptr , а затем деструктор будет запущен для обоих, вы ' Я попытаюсь освободить одну и ту же память два раза, и программа выйдет из строя.

  2. Измените private: на public: в заголовке или с помощью макроса
    , если ваша лицензия разрешает это, вы можете решить свою проблему, отредактировав файл заголовка, который поставляется с реализацией класса . Независимо от того, находится ли исходный код реализации (т.е. cpp-файл класса) под вашим контролем, не имеет значения: достаточно изменить частный на общедоступный для элементов данных (в заголовке) и отлично работает, даже если вам дан двоичный- единственная библиотека, содержащая определение класса. (Для функций-членов изменение доступа иногда меняет свое внутреннее имя, но для MSVS и GCC это нормально. )

  3. Добавление новой функции получения
    При изменении private на public почти всегда нормально (если только вы не полагаетесь на специальные проверки во время компиляции, которые должны нарушить компиляцию, если класс имеет доступ к определенному члену), добавление новой функции получения должно выполняться осторожно. Функция получения должна быть встроенной (и, следовательно, определяться в файле заголовка класса).

  4. reinterpret_cast
    Приведение работает нормально , если вы НЕ приводите указатель к динамическому базовый класс (динамический означает «с виртуальными функциями или базами»), реальный экземпляр которого в момент приведения может быть производным от класса в конкретном фрагменте кода.

  5. protected:
    И на всякий случай вы забыли. C ++ может объявлять члены защищенными: , т.е. доступны только для классов, производных от данного. Это может удовлетворить ваши потребности.

3
ответ дан 6 December 2019 в 07:07
поделиться

I agree with the "edit the source" comment, but I think you should add a method, not just comment out the 'private'.

You must have the declaration of the class, so you presumably have the header but possibly not the .cpp/whatever file. Add an inline member function to the class in a copy of the header, and include this header instead of the original. You should still be able to link to the object file for the inaccessible source code.

Of course this counts as an evil hack, bypassing the protections built into the language rather than working with them. That's why I suggest the minimally evil hack - don't make everything private, and if you can get away with a getter (but no setter) do that. Of course the real minimal evil is not to do it, if there's any way at all to avoid it.

Remember, if this is someone elses class you're working with, the next version might be implemented differently and might not have that member at all.

0
ответ дан 6 December 2019 в 07:07
поделиться

Thank you ... I did want to show the code for my original fix. The reason as someone aluded to is that I cannot change the original code ... so I have to do a jail break.


#include<iostream>
using namespace std;

// Class Objectfoo
// Pretend Objectfoo lives somewhere else ... I cannot open him up

class ObjectFoo 
{
  private:
  int datax; 
  public:
   ObjectFoo() { datax = 100; }
   void get() { cout << datax << endl;}
};

// Class ObjectBar
class ObjectBar 
{
  public:
   int datax;
};

ObjectFoo FOOEY;

ObjectBar* touch_foo(int x, ObjectFoo* foo , ObjectBar* bar)
{
 bar = reinterpret_cast<ObjectBar*>(foo);
 bar->datax = x;
 return bar;
}

int main() 
{
  ObjectBar* bar;

  cout << "Displaying private member in ObjectFoo i.e. ObjectFoo.datax" << endl;
  FOOEY.get();

  cout << "Changing private member " << endl;
  bar = touch_foo(5, &FOOEY, bar);

  cout << "bar->datax = " << bar->datax << endl;

  cout << "Displaying private member in ObjectFoo i.e. ObjectFoo.datax" << endl;
  FOOEY.get();

  return 0;
}

This works ... but I think I want something more generic ... or more flexible.

%

0
ответ дан 6 December 2019 в 07:07
поделиться
Другие вопросы по тегам:

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