【问题标题】:Accessing a member of an object void pointer c++访问对象的成员void指针c ++
【发布时间】:2016-05-24 05:05:51
【问题描述】:

我有一个任务,我必须使用带有 void* 作为数据的节点链表。我会用一个对象填充节点。我想知道在链接列表中之后访问对象成员的某种方法,而不是将其强制转换为类。可能吗?另外,这是我的一部分代码,以防万一它有助于澄清我的问题。

struct Node
{
    void* data_;
    Node* next_;

    Node()
    {
        data_ = 0;
        next_ = 0;
    }
};

class Star
{
private:
    char name_[ENTRY_SZ];
    long temperature_;
    double luminosity_;
    double mass_;
    double radius_;

public:
    static char filePath_[ENTRY_SZ];

    Star(char* name);
    void SetTemperature(char* temp);
    void SetLuminosity(char* lum);
    void SetMass(char* mass);
    void SetRadius(char* rad);
    void PrintToConsole();
    void AppendToFile();
};

我希望能够在 PrintToConsole 函数位于 void* 后调用它。

【问题讨论】:

  • 仅供参考——您不需要链接列表来提出这个问题。您想获取一个 void 指针并将其变成具体的东西。如果不是Star 类型是简单的intdouble,则答案基本相同。

标签: c++ pointers void-pointers


【解决方案1】:

由于这是一项作业,您最好向您的老师/导师询问他们在 C++ 中使用 void* 类型的意图; void* 类型本身并不糟糕,但还有其他方法可以在保持语言一致性的同时获得类似的结果。

直接回答:

我想知道在对象位于链表中之后访问对象成员的某种方法,而不是将其强制转换为类。有可能吗?

是的,这是可能的,但不能使用 void* 成语。以您的代码为例,如果您保留void*,您确实必须转换为适当的类型并确定指向的类型是兼容的,例如:

struct Node
{
    void* data_;
    Node* next_;

    Node()
    {
        data_ = 0;
        next_ = 0;
    }
};

class Star
{
    public:
        void PrintToConsole() {} // empty to avoid not-defined errors
};

int main() {
    Node n;
    n.data_ = new int(42);
    static_cast<Star*>(n.data_)->PrintToConsole(); // this will compile fine, but what happens here is undefined
    delete static_cast<int*>(n.data_); // can't delete void*, have to cast
    return 0;
}

同样,由于这是一项作业,您的教授可能只是想教指针和强制转换或类型系统,而您可能还没有了解 C++ 模板,但既然您问了,这是您使用模板的代码:

template < typename T >
struct Node
{
    T data_;
    Node* next_;

    // use member init list to construct default T object
    Node() : data_(), next_(0)
    {
    }
};

class Star
{
    public:
        void PrintToConsole() {} // empty to avoid not-defined errors
};

int main() {
    Node<Star*> n;
    n.data_ = new Star();
    n.data_->PrintToConsole(); // OK
    delete n.data_; // no cast needed since data_ is a Star* type

    Node<int*> n2;
    n2.data_ = new Star(); // compiler error (data_ is of type int* not Star*)
    n2.data_->PrintToConsole(); // compiler error (int has no member named PrintToConsole)
    delete n.data_;
    return 0;
}

这只是一个简单的例子来说明你在问什么,如果你对这个话题有困惑,最好还是问问你的老师。

希望能有所帮助。

【讨论】:

    【解决方案2】:

    你应该把它投射到课堂上。但是如果你真的不想,你可以使用offsetof 宏:

    宏 offsetof 扩展为 std::size_t 类型的常量,即 的值是从开头的偏移量,以字节为单位 指定类型的对象到其指定成员,包括填充 if 任何。 如果 type 不是标准布局类型,则行为未定义。 如果 member 是静态成员或成员函数,则行为是 未定义。

    但是你应该把它投射到类中。

    编辑:啊,我看到你想访问类的方法。那是不可能的。你应该把它投射到课堂上。

    【讨论】:

    • offsetof 如何帮助调用对象的PrintToConsole 方法?
    • 我看不出offsetof 在这里有什么用处。你能详细说明一下吗?
    【解决方案3】:

    没有。您必须将其强制转换为适当的对象。

    我会质疑使用 void 指针的原因。

    我还建议动态演员可能会更好

    【讨论】:

    • dynamic_cast = 设计失败,极少数例外。
    • @SergeyA - 我同意 - 但对于这个问题,这是我能想到的最好的事情。
    【解决方案4】:

    如果不先投射 void* 的指针,就无法使用它。例如,如果它指向Star,您可以执行以下操作:

    static_cast<Star*>(data_)->PrintToConsole(); // Haha, Star star!
    

    也就是说,在 C++ 中,存储这样的东西是很不寻常的。最好使用模板类,以便获取所需的类型信息。

    【讨论】:

    • 可能他们还没有研究过模板。
    • @Barmar 几乎可以肯定是这样。不过,我仍然认为提及它们是件好事,这样他们就会意识到它们的存在。
    • 谢谢,不知道除了套管还有没有更好的办法。
    猜你喜欢
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多