自定义排序实现会导致链接错误

Custom sort implementation causes link errors

本文关键字:链接 错误 排序 实现 自定义      更新时间:2023-10-16

我想对一些 Bridge 数据进行排序,以便 N(代表没有王牌)出现在 S(代表黑桃)之后。 如果我将所有代码保存在一个文件中,则以下内容有效

class Bridge_lt_str : public std::binary_function<std::string, std::string, bool>
{
public:
struct lt_char
{
const char *tab;
};
char tab[CHAR_MAX - CHAR_MIN + 1];
Bridge_lt_str(const std::locale& L = std::locale::classic())
{
const std::ctype<char>& ct = std::use_facet<std::ctype<char> >(L);
for (int i = CHAR_MIN; i <= CHAR_MAX; ++i)  // cast for char.
tab[i - CHAR_MIN] = static_cast<char>(i); // (char)i 
//Only concerned with ordering C, D, H, S, N=NT.
tab['N' - CHAR_MIN] = tab['Z' - CHAR_MIN];
ct.toupper(tab, tab + CHAR_MAX - CHAR_MIN + 1);
}
};
Bridge_lt_str lt_str;

bool isDenomLess(std::string& lhs, std::string& rhs)
{//NT is the highest denomination.  Otherwise, everything sorts normally.
if (lhs[0] == rhs[0]) return lt_str.tab[lhs[1] - CHAR_MIN] < lt_str.tab[rhs[1] - CHAR_MIN];
return lhs[0] < rhs[0];
}

我想将所有这些因素分解到一个单独的包含文件中 只需从主代码调用 isDenomLess 排序函数,例如

std::sort(tks.begin(), tks.end(), &isDenomLess);

这适用于其他一些排序函数,例如

sort(v_keys.begin(), v_keys.end(), order_by_score_freq);

我已经在单独的头文件中内联了这些函数

inline bool order_by_score_freq(const Result & r1, const Result & r2);
inline bool isDenomLess(std::string& lhs, std::string& rhs);

但是,大概是因为选项卡数组初始化,我尝试过的任何事情都会给出链接错误

LNK2005: "class Bridge_lt_str lt_str" (?lt_str@@3VBridge_lt_str@@A) already defined in Bridge.obj

任何关于合适包括结构的帮助,非常感谢!

问题出在以下行上:

Bridge_lt_str lt_str;

将其更改为:

extern Bridge_lt_str lt_str;

然后在您的.cpp之一中,文件具有:

Bridge_lt_str lt_str;

拥有代码(在标头中就可以了,只要定义在类体内或使用"内联"说明符声明即可。

您可以清理它并将其拆分为单独的文件,这从组织的角度来看很有帮助。

.h头文件中,您尝试并专注于布局大局:

class Bridge_lt_str : public std::binary_function<std::string, std::string, bool>
{
public:
struct lt_char
{
const char *tab;
};
Bridge_lt_str(const std::locale& L = std::locale::classic());
char tab[CHAR_MAX - CHAR_MIN + 1];
};
bool isDenomLess(std::string& lhs, std::string& rhs);

值得注意的是,从面向对象设计的角度来看,您希望避免公开其他代码不应访问的内部结构。保留这些privateprotected,具体取决于您希望如何锁定访问权限。

然后在bridge_lt_str.cpp实现文件中定义这些工作原理:

Bridge_lt_str::Bridge_lt_str(const std::locale& L)
{
const std::ctype<char>& ct = std::use_facet<std::ctype<char> >(L);
for (int i = CHAR_MIN; i <= CHAR_MAX; ++i)
tab[i - CHAR_MIN] = static_cast<char>(i);
//Only concerned with ordering C, D, H, S, N=NT.
tab['N' - CHAR_MIN] = tab['Z' - CHAR_MIN];
ct.toupper(tab, tab + CHAR_MAX - CHAR_MIN + 1);
}
bool isDenomLess(std::string& lhs, std::string& rhs)
{
if (lhs[0] == rhs[0])
return lt_str.tab[lhs[1] - CHAR_MIN] < lt_str.tab[rhs[1] - CHAR_MIN];
return lhs[0] < rhs[0];
}

如果您不打算更改它们,请尝试将内容标记为const您的论点。isDenomLess函数不会修改这些字符串,因此const std::string&是这些参数的合适类型。省略const通常传达修改它们的意图。当那些试图使用您的函数的人只有一个const字符串并且无缘无故地需要一个非const字符串时,它也会惹恼那些尝试使用您的函数的人。

在其他一些文件(如main.cpp)中,您可以使用您的类:

int main() {
Bridge_lt_str lt_str;
return 0;
}

您需要链接来自main.cpp的两个编译器输出(例如main.o)和来自另一个(例如bridge_lt_str.o)一起。这是任何非平凡C++程序的标准,因此您应该有一个Makefile或等效项来自动为您执行此操作。