是否可以将类型转换为C++方法或在方法中确定类型?

5f0d552i  于 2023-01-28  发布在  其他
关注(0)|答案(4)|浏览(174)

我正在尝试自己实现一个任意类型的数据列表,我想根据数据类型打印这个列表,在这一点上,我已经测试了整数和字符,要打印这些类型的列表,有两个方法print_intprint_char,这取决于要显示的数据类型,我的问题是,有没有可能只定义一个方法print,它将根据我的列表的数据类型打印,而不创建类模板(不像List<type> ...)?我的意思是没有这个类定义:

template <class T>
class List{
  T *data;
  List *next;
  ...

**-----------------------更新------------

最后,我找到了一个解决方案,它使我能够动态检查C中的类型(使用dynamic_cast,请参阅公认的答案)。不幸的是,许多人错误地认为C受到严重限制。这证明了我的问题,许多人不知道答案,只会用减号来回答。

dy2hfwbg

dy2hfwbg1#

如果你想在列表中存储 any 类型而不丢失类型信息,你也可以尝试多态方法:

class NodeBase
{
public:
    virtual ~NodeBase();
    virtual void print() = 0;

    template <typename T>
    void append(T t);

protected:
    NodeBase* next;

    void appendNode(NodeBase* node);
};

template<typename T>
class Node : public NodeBase
{
public:
    void print() override { ... }

private:
    T data;
};

template <typename T>
void NodeBase::append(T t) // as being template, needs to remain in header!
{
    appendNode(new Node<T>(t));
}

最后,print实现可能使用另一个函数的不同重载来实际打印data值。
边注:我倾向于将当前的List类重命名为Node,并使其成为一个新创建的List类的内部类,该类将在内部管理节点。如果您将指向head的唯一指针移动到的后继类,当前的列表实现很容易导致内存泄漏。

6qftjkof

6qftjkof2#

这是一个非常简单的列表!

template <class T>
class List{
   T*    data;
   List* next;

   void print() {
       std::cout << "[ ";
       print(this, "");
       std::cout << " ]\n";
   }
   void print(List* node, std::string const& sep) {
       if (node == nullptr) {
           return;
       }
       std::cout << sep << node->data;
       print(node->next, ", ");
   }
}

这应该适用于任何支持普通流输出的类型。现在这应该可以让你开始了,但我会改变你实现list的方式很多。把list想象成一组节点的所有者。节点保存数据,但不是列表。

tpxzln5u

tpxzln5u3#

让我们尝试一种不同的方法:指向打印函数的指针。
让我们为print函数创建一个同义词:

typedef (void) (*(Ptr_Print_Function)(std::ostream& output, void * node_data));

由于每个节点可以是不同的类型,因此必须正确地初始化打印函数。

struct Node
{
  void * p_data;
  Node * prev_node;
  Node * next_node;
  Ptr_Print_Function p_printer;
};

以下是一些附加转发声明:

void Print_Integer_Node(std::ostream& output, void * p_data);
void Print_Char_Node(std::ostream& output, void * p_data);

下面是将节点打印到std::cout的代码片段:

Node * p_node;
//... node search / initialize
(p_node->p_printer)(std::cout, p_node->p_data);

编辑1:数据继承

恕我直言,一个更干净的方法是对数据使用继承和基类(接口)。

struct List_Data_Interface
{
    virtual void print_data(std::ostream& output) = 0;
    void * p_data;
};

struct Node_Version_2
{
    List_Data_Interface * p_data;
    Node_Version_2 *      p_prev;
    Node_Version_2 *      p_next;
};

在上面的模型中,我们假设每个节点的数据都有一个print方法和一个指向某些数据的指针。
整数数据示例:

struct Integer_Data : public List_Data_Interface
{
  void print_data(std::ostream& output)
  {
      int * p_int_data = (int *) p_data;
      output << *p_int_data;
  }
};

下面是一些关于如何使用上面的Node_Version_2打印节点的代码:

//...
Node_Version_2 p_node;
//... initialize or find the node.
p_node->print_data(std::cout);

通过 * 多态性 *,将选择正确的打印函数。

0s0u357o

0s0u357o4#

不幸的是,许多人错误地认为C是非常有限的。这就证明了我的问题,许多人不知道答案,就给它加上了减号。幸运的是,我找到了一个解决方案/答案,它使我能够**使用dynamic_cast在C**中动态检查类型。(它等于类型TypeToCheck吗?)不幸的是,这只对类类型有效。
我认为这很有帮助,所以实现如下:
列表类(list.h):

#pragma once
#include <iostream>

using namespace std;

class Base {
public:
    virtual ~Base() {};
};

class Char : public Base {
    char value;
public:
    Char(char value) : value(value) {};

    friend ostream& operator << (ostream& stream, const Char* self) {
        return stream << "'" << self->value << "'";
    };
};

class Int : public Base {
    int value;
public:
    Int(int value) : value(value) {};

    friend ostream& operator << (ostream& stream, const Int* self) {
        return stream << self->value;
    };
};

class Float : public Base {
    float value;
public:
    Float(float value) : value(value) {};

    friend ostream& operator << (ostream& stream, const Float* self) {
        return stream << self->value;
    };
};

class List
{
    Base* data = nullptr;
    List* next = nullptr;
public:
    List() {};
    List(Base* data):data(data) {};

    void set_next(List* next) {this->next = next;};

    void append(Base* data) {
        List *last_element = this;
        while(last_element->next)
            last_element = last_element->next;

        last_element->set_next(new List(data));
    };

    void print_element(){
        if (dynamic_cast<Char*>(data))
            std::cout << (Char*)data << "(Char)";
        else if (dynamic_cast<Int*>(data))
            std::cout << (Int*)data << "(Int)";
        else if (dynamic_cast<Float*>(data))
            std::cout << (Float*)data << "(Float)";
    }
    void print() {
        bool is_first = true;
        
        cout << endl << "list " << static_cast<void*>(this) << " [";

        List* element = this;
        while(element) {
            if (is_first)
                is_first = !is_first;
            else
                cout << ", ";
            element->print_element();
            element = element->next;
        }
        cout << "]" << endl;
    };
};

测试文件(main.cpp):

#include "list.h"

int main()
{
    List myList(new Int(10));
    myList.append(new Float(1.203f));
    myList.append(new Int(12));
    myList.append(new Char('f'));
    
    myList.print();

    return 0;
}

结果为:

list 000000000014F6D8 [10(Int), 1.203(Float), 12(Int), 'f'(Char)]

相关问题