【发布时间】:2021-03-04 06:38:55
【问题描述】:
我正在尝试自己实现任何类型的数据列表,并且我想根据数据类型打印此列表。至此,我已经测试了整数和字符。要打印这些类型的列表,有两种方法print_int 和print_char,具体取决于所显示的数据类型。我的问题是,是否可以只定义一种方法print,根据我列表的数据类型打印而不创建类模板(不像List<type> ...)?
我的意思是没有这个类定义:
template <class T>
class List{
T *data;
List *next;
...
(我不使用类模板,因为在 void * 类型为 data 的情况下,可以混合整数、字符、字符串等)
或者我可以将数据类型作为参数传递或确定方法中的类型?
我已尝试使用C++ pass variable type to function 中接受的答案中的模板,仅用于以下形式的函数print:
template <typename T>
void List::print()
{
printf("\nlist %p: [", this);
bool is_first = true;
List* element = this;
while(element)
{
if (is_first)
is_first = !is_first;
else
printf(", ");
printf("%i", *(T*)element->data);
element = element->next;
}
printf("]\n");
}
但我在使用g++ 编译器时出错:
对 `void List::print
()' 的未定义引用
collect2: 错误:ld 返回 1 个退出状态
这是我的文件: main.cpp
#include "list/list.h"
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
List myList(new int(10));
myList.append(new int(120));
myList.append(new int(56));
myList.print<int>(); //!
myList.print_int();
List myListChar(new char('f'));
myListChar.append(new char(48));
myListChar.append(new char('g'));
myListChar.print_int();
myListChar.print_char();
return 0;
}
列表的实现(list.h):
#ifndef LIST_H
#define LIST_H
class List
{
void *data;
List *next;
public:
List(void*);
void append(void*);
void print_int();
void print_char();
template <typename T> void print();
};
#endif // LIST_H
list.cpp:
#include "list.h"
#include <stdio.h>
List::List()
{
data = NULL;
next = NULL;
}
List::List(void *data)
{
this->data = data;
next = NULL;
}
void List::append(void *data)
{
List *last_element, *element = this;
while(element)
{
last_element = element;
element = element->next;
}
List* next_element = new List(data);
last_element->next = next_element;
}
void List::print_int()
{
printf("\nlist %p: [", this);
bool is_first = true;
List* element = this;
while(element)
{
if (is_first)
is_first = !is_first;
else
printf(", ");
printf("%i", *(int*)element->data);
element = element->next;
}
printf("]\n");
}
void List::print_char()
{
printf("\nlist %p: [", this);
bool is_first = true;
List* element = this;
while(element)
{
if (is_first)
is_first = !is_first;
else
printf(", ");
printf("%c", *(char*)element->data);
element = element->next;
}
printf("]\n");
template <typename T>
void List::print()
{
printf("\nlist %p: [", this);
bool is_first = true;
List* element = this;
while(element)
{
if (is_first)
is_first = !is_first;
else
printf(", ");
printf("%i", *(T*)element->data);
element = element->next;
}
printf("]\n");
}
抱歉这个愚蠢的问题,提前谢谢你!
-------------- 更新 ----- ---------
感谢https://stackoverflow.com/users/7582247/ted-lyngmo (Why can templates only be implemented in the header file?) 的评论和https://stackoverflow.com/users/1312382/aconcagua 的回答,将代码template <typename T> void List::print() 移动到标题避免了错误undefined reference to void List::print
不要忘记模板不能与标题分开。
-------------- 最后------ ---------
按照@Aconcagua 的回答,我的列表实现的工作(未优化)版本(不同类型的存储,考虑到它们的打印)如下所示:
list.h:
#include<iostream>
using namespace std;
class NodeBase
{
public:
// virtual ~NodeBase();
virtual void print_elem() = 0;
template <typename T>
void append(T t);
void print();
protected:
NodeBase* next;
void appendNode(NodeBase* node);
};
template<typename T>
class List : public NodeBase
{
T data;
public:
List(T _data)
{
data = _data;
next = nullptr;
}
void print_elem() override
{
cout << this->data;
}
};
template <typename T>
void NodeBase::append(T t) // as being template, needs to remain in header!
{
appendNode(new List<T>(t));
}
void NodeBase::appendNode(NodeBase* node)
{
NodeBase *last_element, *element = this;
while(element)
{
last_element = element;
element = element->next;
}
last_element->next = node;
}
void NodeBase::print()
{
cout << "list at " << static_cast<void*>(this) << ": [";
bool is_first = true;
NodeBase *element = this;
while(element)
{
if (is_first)
is_first = !is_first;
else
cout << ", ";
element->print_elem();
element = element->next;
}
cout << "]" << endl;
}
带有测试文件main.cpp:
#include "list/list.h"
int main()
{
List myNode(10);
myNode.append(20);
myNode.append(std::string("sdfsdv"));
myNode.append('f');
myNode.append(2.4);
myNode.print();
}
【问题讨论】:
-
一般经验法则:当数据类型改变但算法没有改变时,考虑使用
template。 -
是的,您使用模板。您需要一个接受任何类型的打印函数,它会自动打印该类型。它已经存在。
operator<<() -
stackoverflow.com/users/225074/thomas-matthews 这是否意味着唯一的解决方案是避免
void *并使用类模板? stackoverflow.com/users/14065/martin-york - 再次operator<<()需要转换void* -
关于“对
void List::print<int>()的未定义引用”:这可能会有所帮助:Why can templates only be implemented in the header file? -
可以使用
void*,但很难做到正确和安全。如果您绝对必须在编译时知道类型并且在运行时知道类型,请考虑使用std::variant或std::any,而不是尝试手动完成所有操作。
标签: c++