将指向不同变量类型的指针传递给函数,并在以后的赋值中重用它们

Passing pointers to different variable types to a function and reuse them later for assignmet

本文关键字:赋值 变量 类型 指针 函数      更新时间:2023-10-16

在一个基于GUI的项目中,我需要Page1标记一个变量要更改并调用Page2, Page2读取用户的输入并使用新值更新标记的变量。变量类型总是不同的,并且所有变量都由外部链接库保存。

如何实现这一点,而不创建fname_uint8, fname_uint16, fname_giventype变量的标记和设置?

这个例子总结了这个场景:

有一个VarHolder类,它包含了很多结构体和很多变量,例如:

class VarHolder 
{
public:
    typedef struct {
        int8_t var1;
        int16_t var2;
        int32_t var3;
        char str1[40];
        float var4;
    } struct1_t;
    /* ...continues... */
struct1_t struct1;
}

现在类FirstStage想要标记一个变量进行更改,并调用类Committercommitter_instance实例的成员

class FirstStage 
{
    /* ... */
    void doFirstStage(void)
    {
        /* Globally defined committer instance */
        g_committer_instance->mark_var_change(&varholder_instance->struct1.var1);
    }
}

Committer::mark_var_change(T*)定义如下:

template <typename T>
void Committer::mark_var_change(T *var)
{
    /* Store a pointer to the variable */
    /* SAVE SOMEWHERE PRESERVING TYPE */ = var;
}

最后,SecondStage的成员想要使用一个现在可用的值来更新通过同一个g_committer_instance标记的变量,像这样:

class SecondStage
{
    /* ... */
    template <typename T>
    void doSecondStage(T new_value)
    {
        g_committer_instance->commit_change(new_value);
    }
}

其中Committer::commit_change(T)定义如下:

template <typename T>
void Committer::commit_change(T new_value)
{
    /* Dereferencing the previously stored pointer */
    *(/*WHATEVER I STORED BEFORE*/) = new_value;
}

当然,我无法做到的是实现一个类型独立的"标记和检索器",它可以根据变量的地址无缝地更新变量。如有任何建议,不胜感激。

MCVE

### varholder.h
#include <stdint.h>
class VarHolder
{
public:
VarHolder() {}
virtual ~VarHolder() {}
typedef struct 
{
int8_t var1;
uint8_t var2;
int64_t var3;
char str1[40];
} struct1_t;
struct1_t struct1;
}
### firststage.h
#include global.h
class FirstStage 
{    
public:
    FirstStage() {}
    ~FirstStage() {}
    void doFirstStage(void)
    {
        /* Globally defined committer instance */
        g_committer_instance->mark_var_change(&varholder_instance->struct1.var1);
    }
}
### secondstage.h
#include global.h
class SecondStage
{
    public:
    SecondStage() {}
    ~SecondStage() {}
    template <typename T>
    void doSecondStage(T new_value)
    {
        g_committer_instance->commit_change(new_value);
    }
}
### committer.h
#include global.h
class Committer
{
    public:
    Committer() {}
    ~Committer() {}
template <typename T>
void Committer::mark_var_change(T *var)
{
    /* Store a pointer to the variable */
    /* SAVE SOMEWHERE PRESERVING TYPE */ = var;
}
template <typename T>
void Committer::commit_change(T new_value)
{
    /* Dereferencing the previously stored pointer */
    *(/*WHATEVER I STORED BEFORE*/) = new_value;
}
}

### global.h
#include varholder.h
#include committer.h
extern Committer *g_committer_instance;
extern VarHolder *varholder_instance;
### main.cpp
#include global.h
#include varholder.h
#include firststage.h
#include secondstage.h

Committer *g_committer_instance;
VarHolder *varholder_instance;
int main() 
{
g_committer_instance = new Committer();
varholder_instance = new VarHolder();
FirstStage *fstage = new FirstStage();
SecondStage *sstage = new SecondStage();
int8_t var_new = 100;
/* First stage */
fstage->doFirstStage();
/* Second stage */
sstage->doSecondStage(var_new);
return 0;
}

您可以单独使用void*(不安全)或使用typeid:

class Committer
{
public: 
    template <typename T>
    void mark_var_change(T *var)
    {
        mPointer = var;
        mTypeInfo = &typeid(T*);
    }
    template <typename T>
    void commit_change(T new_value)
    {
        if (*mTypeInfo != typeid(T*)) {
            throw std::runtime_error("Bad type");
        }
        if (mPointer == nullptr) {
            throw std::runtime_error("nullptr was stocked");
        }
        *reinterpret_cast<T*>(mPointer) = new_value;
    }
private:
    void* mPointer = nullptr;
    const std::type_info* mTypeInfo = nullptr;
};
  • 与类型id Live example

或更安全的boost::any,它自己管理类型:

class Committer
{
public: 
    template <typename T>
    void mark_var_change(T *var)
    {
        mPointer = var;
    }
    template <typename T>
    void commit_change(T new_value)
    {
        T* pointer = boost::any_cast<T*>(mPointer); // throw with bad type
        if (pointer == nullptr) {
            throw std::runtime_error("nullptr was stocked");
        }
        *pointer = new_value;
    }
private:
    boost::any mPointer;
};

生活例子