передача структуры как пустоты * - PullRequest
0 голосов
/ 02 августа 2020

ALL,

В Foo.h:

struct Properties1
{
    std::string name;
    int size;
};

struct Properties2
{
    std::string name1, name2;
    int size1, size2;
}

int my_func(void *param);

В Foo. cpp:

void *properties;
if( type == 0 )
{
    Properties1 prop;
    prop.name = "abc";
    prop.size = 5;
    properties = ∝
}
if( type == 1 )
{
    Properties2 prop;
    prop.name1 = "def";
    prop.name2 = "Second property";
    prop.size1 = 8;
    prop.size2 = 10;
    properties = ∝
}
//    Properties p = *static_cast<Properties *>( properties );
int res = my_func(properties);

Properties1 и properties2 являются независимыми структурами.

Затем my_fun c выполнит некоторую обработку объекта различных свойств.

По какой-то причине объект p недействителен.

Мне нужно передать различные параметры функции и поэтому хотел использовать void *.

Или, может быть, это проще в C ++ 11?

TIA !!

[EDIT]

Итак , в основном я пишу приложение GUI с разными объектами, которые отображаются в окне. У каждого объекта есть свой набор свойств. И я разрешаю пользователю редактировать эти свойства в диалоговом окне типа записной книжки. У меня есть несколько страниц, которые заполняются из соответствующего объекта свойств.

Таким образом, код диалогового окна является постоянным, и он находится внутри my_fun c. Однако в зависимости от типа свойств я представляю разные заданные страницы.

В основном my_fun c:

- Create a dialog (this is inside my_func)
- In the dialog constructor I pass the type and the properties object.
- I create a notebook control and based on the type I add the notebook pages.

[/ EDIT]

Ответы [ 3 ]

3 голосов
/ 02 августа 2020

Если вам нужно a void* в вашей программе, ваш дизайн сломан! Есть несколько причин, чтобы по-прежнему использовать void*, но все они действительны только в том случае, если вам приходится иметь дело со старыми интерфейсами библиотеки в стиле c. Если вы пишете свои собственные функции, всегда неправильно использовать void* без каких-либо исключений.

Итак, в основном я пишу приложение GUI с разными объектами, которые появляются в окне .

Это именно то решение, которое у вас должно быть! Объекты должны представлять сами . Это означает: не пишите код, который "знает" что-то об объекте. Если вы сделаете это, сведения о классе или структуре будут не только в структуре / классе, но и в коде, который имеет дело с этими объектами этого класса / структуры. Это нарушенный дизайн и полная противоположность OOP.

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

В вашем случае вы хотите иметь своего рода «редактор», поэтому давайте попробуем написать минимальный пример редактора. Я не предоставил ничего gui, так как это позволяет увеличить размер кода здесь!

Существует довольно распространенный паттерн, который мы называем сериализатором . Основная функциональность c состоит в том, чтобы позволить самим объектам «какие элементы» обрабатывать информацию (функция Serialize) и классам / объектам-обработчикам, которые выполняют эту работу EditSerializer и PrintSerializer.

Теперь вам просто нужно предоставить объекты-обработчики для объектов, которые должны обрабатываться.

Полный пример:

struct Properties1
{
    std::string name;
    int size;

    template < typename Serializer >
        void Serialize( Serializer& ser )
        {
            // Here we only provide the "information" which data we have.
            // at this line of code, we have no idea what a *serializer* 
            // will do with our data.
            ser & name & size;
        }
};

struct Properties2
{
    std::string name1, name2;
    int size1, size2;

    template < typename Serializer >
        void Serialize( Serializer& ser )
        {
            ser & name1 & name2 & size1 & size2; 
        }

};

struct EditSerializer
{
    // Here we don't know which elements we get, but we know
    // what we want to do with all of them!
    // Print them and lets the user enter a new value
    template < typename E > 
    EditSerializer& operator &( E& element ) 
    {   
        std::cout << "Old value:" << element << std::endl; 
        std::cout << "Please enter new value " << std::endl;
        std::cin >> element;
        return *this;
    }
};

struct PrintSerializer
{
    template < typename E >
    PrintSerializer& operator &( E& element )
    {
        std::cout << "Value" << element << std::endl;
        return *this;
    }
};

int main()
{
    Properties1 p1{"Hallo",100};
    Properties2 p2{"Another","Example",987,456};

    EditSerializer eser;
    p1.Serialize( eser );
    p2.Serialize( eser );

    PrintSerializer pser;
    p1.Serialize( pser );
    p2.Serialize( pser );
}

Теперь вы можете заменить классы сериализатора также на свои gui составные части. Вы также можете предоставить дополнительные теги в своих классах данных, которые могут предоставлять имена или редактировать позиции полей или что угодно, что вам нужно.

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

Код использует operator &, чтобы писать код более умным, поскольку мы используем вызов функции. То, что мы используем &, довольно часто встречается в шаблоне сериализатор . Но вы можете использовать любой оператор, который вам нравится, и даже прямой вызов функции. Использование оператора - это удобная функция.

1 голос
/ 02 августа 2020

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

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

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

#include <memory>
#include <string>
#include <iostream>

struct Properties1
{
    std::string name;
    int size;
};

struct Properties2
{
    std::string name1, name2;
    int size1, size2;
};

struct PropertiesHandler
{
       virtual ~PropertiesHandler() {}
       virtual void HandleProperty() = 0;
};

class PropertiesHandlerProp1 : public PropertiesHandler
{
   Properties1 m_prop;
   public:
       Properties1& getProp() { return m_prop; }
       void HandleProperty() 
       {
          std::cout << m_prop.name << " " << m_prop.size << "\n";
       }
};
      
class PropertiesHandlerProp2 :  public PropertiesHandler
{
   Properties2 m_prop;
   public:
       Properties2& getProp() { return m_prop; }
       void HandleProperty() 
       {
          std::cout << m_prop.name1 << " " << m_prop.size1 << "\n" << m_prop.name2 << " " << m_prop.size2 << "\n";
       }
};

int my_func(std::unique_ptr<PropertiesHandler>& ptr)
{
     // Create the dialog
     //... 
     // Call handling function
     ptr->HandleProperty();
     //...
     return 1;
}

int main()
{  
    std::unique_ptr<PropertiesHandler> propPtr;
    int type = 1;
    if( type == 0 )
    {
        auto ptr = std::make_unique<PropertiesHandlerProp1>(); 
        auto& prop = ptr->getProp();
        prop.name = "abc";
        prop.size = 10;
        propPtr = std::move(ptr);
   }
   else
   if( type == 1 )
   {
        auto ptr = std::make_unique<PropertiesHandlerProp2>(); 
        auto& prop = ptr->getProp();
        prop.name1 = "def";
        prop.name2 = "Second property";
        prop.size1 = 8;
        prop.size2 = 10;

        propPtr = std::move(ptr);
  }
  my_func(propPtr);  // this will use the second property
}

Вывод:

def 8
Second property 10

Обратите внимание, что my_func ничего не знает о name1, name2, et c. Он даже не знает, что обрабатывает объект PropertiesHandlerProp2. Он не должен знать эти вещи - вся эта информация находится в соответствующих объектах.

0 голосов
/ 02 августа 2020
Properties *p2 = new Propertes;
p2->name = "abc";
p2->size = 5;
properties = p2;
// don't forget to delete p at some point!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...