未解决的外部链接问题
unresolved externals- linking issues
目前正在学习 C++ 课程,获得了一个关于模板 classes 和函数的项目-
收到此错误消息,无法确定来自何处,所有文件都可以正常编译。
仔细检查所有声明等
错误消息:
Menu.obj : error LNK2019: 未解析的外部符号 "class std::basic_ostream & __cdecl operator<<(class std::basic_ostream &,class CSet const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@ std@@@std@@AAV01@ABV?$CSet@J@@@Z) 在函数“private: bool __thiscall Menu::check(void)”中引用 (?check@Menu@@AAE_NXZ)
代码:
CSET // 类型 t 的集合,头文件
#ifndef __C_SET_H__
#define __C_SET_H__
#include <iostream>
using namespace std;
template <class T>
class CSet
{
public:
CSet() { m_length = 0; m_setArr = NULL; }//ctor
CSet(const CSet& set);//cctor
~CSet() { delete[] m_setArr; }
//--operators--//
CSet& operator=(const CSet& );
CSet& operator+=(const T& );
CSet& operator-=(const T& );
CSet& operator-(const CSet& )const;
friend ostream& operator<<(ostream&, const CSet& );//ouput
//--methods--//
const CSet UNION(const CSet& );
const CSet INTERSECT(const CSet& );
private:
int m_length;
T* m_setArr;
int appears(const T& );//private method check index of T in setArr
};
template <class T>
CSet<T>::CSet(const CSet& set)//cctor
{
*this = set;
}
template <class T>
CSet<T>& CSet<T>::operator=(const CSet& set)
{
m_length = set.m_length;
m_setArr = set.m_setArr;
return *this;
}
template <class T>
CSet<T>& CSet<T>::operator+=(const T& val)
{
if (appears(val) == -1)
return *this;
try
{
T* arr = new T[m_length + 1];
for (int i = 0; i < m_length; i++)
arr[i] = m_setArr[i];
arr[m_length] = val;
m_length++;
delete[] m_setArr;
m_setArr = arr;
return *this;
}
catch (bad_alloc)
{
cout << "Memory Allocation Failed!" << endl;
return *this;
}
}
template <class T>
CSet<T>& CSet<T>::operator-=(const T& val)
{
int index = appears(val);
if (index == -1)
return *this;
m_length--;
try
{
T* arr = new T[m_length];
int j = 0;//index
for (int i = 0; i < m_length; i++)
{
if (i == index)
continue;
arr[j] = m_setArr[i];
j++;
}
delete[] m_setArr;
m_setArr = arr;
return *this;
}
catch (bad_alloc)
{
cout << "Memory Allocation Failed!" << endl;
return *this;
}
}
template <class T>
CSet<T>& CSet<T>::operator-(const CSet& set)const
{
CSet copy;
copy.m_length = m_length;
copy.m_setArr=m_setArr;
copy.INTERSECT(set);
CSet copy2=set;
for (int i = 0; i < copy.m_length; i++)
copy2.operator-=(copy.m_setArr[i]);
return copy2;
}
template <class T>
ostream& operator<<(ostream& os, const CSet<T>& set)
{
if (set.m_length == 0)
os << "The set is empty!" << endl;
else{
os << '(';
int i;
for (i = 0; i < set.m_length - 1; i++)
os << set.m_setArr[i] << ',';
os << set.m_setArr[i] << ')' << endl;
}
return os;
}
template <class T>
const CSet<T> CSet<T>::UNION(const CSet& set)
{
CSet copy;
copy.m_length = m_length;
copy.m_setArr = m_setArr;
for (int i = 0; i < set.m_length; i++)
copy.operator+=(set.m_setArr[i]);
return copy;
}
template <class T>
const CSet<T> CSet<T>::INTERSECT(const CSet& set)//private
{
CSet copy;
copy.m_length = m_length;
copy.m_setArr = m_setArr;
for (int i = 0; i < set.m_length; i++)
copy.operator-=(set.m_setArr[i]);
return copy;
}
template <class T>
int CSet<T>::appears(const T& val)//private
{
for (int i = 0; i < m_length; i++)
if (m_setArr[i] == val)
return i;
return -1;
}
#endif
MENU//打印并显示集合菜单
H 文件
#ifndef __MENU_H__
#define __MENU_H__
#include"CSet.h"
#include <iostream>
using namespace std;
class Menu
{
public:
Menu();//prints menu
private:
//--members--//
CSet<long> longSet;
CSet<char> chSet1;
CSet<char> chSet2;
CSet<string> strSet;
//--methods--//
bool check();
void printSetsOp();
void addRemoveElement(bool);
void difference();
};
#endif
MENU.CPP
#include "Menu.h"
#include "CSet.h"
#include <iostream>
using namespace std;
Menu::Menu()
{//menu print
do {
//show the menu until the user wants to exit
cout << "================MENU================" << endl;
...
} while (check());//as long as the user doesnt want to exit
}
bool Menu::check()
{
int choice;
cin >> choice;//user input
switch (choice)
{
case 1:
{
...
return true;//keep the menu loop going
}
.
.
.
case 7:
{//exit
cout << "Goodbye!" << endl;
return false;//exit the program
}
default:
{//invalid number
cout << "please enter a valid number!" << endl;
return true;//keep the menu loop going
}
}
}
void Menu::printSetsOp()
{
//print options
}
void Menu::addRemoveElement(bool add)
{
printSetsOp();//print scnd menu
int choice;
cin >> choice;//which set
switch (choice)
{
case 1:
{//add or remove elements, each type seperatly
long elm;
cout << "Insert number = ";
cin >> elm;
add ? longSet.operator+=(elm) : longSet.operator-=(elm);
return;
}
case 2:
case 3:
{
char ch;
cout << "Insert character = ";
cin >> ch;
if (add)
(choice == 2) ? chSet1.operator+=(ch) : chSet2.operator+=(ch);
else
(choice == 2) ? chSet1.operator-=(ch) : chSet2.operator-=(ch);
return;
}
default:
{//invalid number
cout << "please enter a valid number!" << endl;
return;//keep the menu loop going
}
}
}
不知道是什么原因导致此错误,所以几乎所有内容都已发布。
谢谢
问题是您 CSet
的朋友 operator<<
命名的函数与您的模板 operator<<
不同。这实际上声明了一个新的 non-template 函数,它最终成为比模板函数更好的候选者,但是没有定义这样的函数,因此出现链接错误。
您可以通过使友元声明引用此运算符针对特定 CSet<T>
的完全特化来解决此问题。为此,必须已经声明模板函数,这需要 CSet
的前向声明。所以,你会做这样的事情:
template <class T> class CSet;
template <class T>
ostream& operator<<(ostream& os, const CSet<T>& set)
{
// implementation here
}
template <class T>
class CSet {
// all of your other stuff...
// Add <> to have the friend declaration refer to a specific operator<< instantiation
// With <>, T is deduced. You can also say <T> instead.
friend ostream& operator<< <>(ostream&, const CSet& );
};
请注意,当您在模板类型中声明非模板友元函数时,大多数编译器应该警告您,因为它会导致您遇到的问题。确保您的编译器警告已启用。
warning: friend declaration 'std::ostream& operator<<(std::ostream&, const foo<T>&)' declares a non-template function
目前正在学习 C++ 课程,获得了一个关于模板 classes 和函数的项目- 收到此错误消息,无法确定来自何处,所有文件都可以正常编译。 仔细检查所有声明等
错误消息:
Menu.obj : error LNK2019: 未解析的外部符号 "class std::basic_ostream
代码: CSET // 类型 t 的集合,头文件
#ifndef __C_SET_H__
#define __C_SET_H__
#include <iostream>
using namespace std;
template <class T>
class CSet
{
public:
CSet() { m_length = 0; m_setArr = NULL; }//ctor
CSet(const CSet& set);//cctor
~CSet() { delete[] m_setArr; }
//--operators--//
CSet& operator=(const CSet& );
CSet& operator+=(const T& );
CSet& operator-=(const T& );
CSet& operator-(const CSet& )const;
friend ostream& operator<<(ostream&, const CSet& );//ouput
//--methods--//
const CSet UNION(const CSet& );
const CSet INTERSECT(const CSet& );
private:
int m_length;
T* m_setArr;
int appears(const T& );//private method check index of T in setArr
};
template <class T>
CSet<T>::CSet(const CSet& set)//cctor
{
*this = set;
}
template <class T>
CSet<T>& CSet<T>::operator=(const CSet& set)
{
m_length = set.m_length;
m_setArr = set.m_setArr;
return *this;
}
template <class T>
CSet<T>& CSet<T>::operator+=(const T& val)
{
if (appears(val) == -1)
return *this;
try
{
T* arr = new T[m_length + 1];
for (int i = 0; i < m_length; i++)
arr[i] = m_setArr[i];
arr[m_length] = val;
m_length++;
delete[] m_setArr;
m_setArr = arr;
return *this;
}
catch (bad_alloc)
{
cout << "Memory Allocation Failed!" << endl;
return *this;
}
}
template <class T>
CSet<T>& CSet<T>::operator-=(const T& val)
{
int index = appears(val);
if (index == -1)
return *this;
m_length--;
try
{
T* arr = new T[m_length];
int j = 0;//index
for (int i = 0; i < m_length; i++)
{
if (i == index)
continue;
arr[j] = m_setArr[i];
j++;
}
delete[] m_setArr;
m_setArr = arr;
return *this;
}
catch (bad_alloc)
{
cout << "Memory Allocation Failed!" << endl;
return *this;
}
}
template <class T>
CSet<T>& CSet<T>::operator-(const CSet& set)const
{
CSet copy;
copy.m_length = m_length;
copy.m_setArr=m_setArr;
copy.INTERSECT(set);
CSet copy2=set;
for (int i = 0; i < copy.m_length; i++)
copy2.operator-=(copy.m_setArr[i]);
return copy2;
}
template <class T>
ostream& operator<<(ostream& os, const CSet<T>& set)
{
if (set.m_length == 0)
os << "The set is empty!" << endl;
else{
os << '(';
int i;
for (i = 0; i < set.m_length - 1; i++)
os << set.m_setArr[i] << ',';
os << set.m_setArr[i] << ')' << endl;
}
return os;
}
template <class T>
const CSet<T> CSet<T>::UNION(const CSet& set)
{
CSet copy;
copy.m_length = m_length;
copy.m_setArr = m_setArr;
for (int i = 0; i < set.m_length; i++)
copy.operator+=(set.m_setArr[i]);
return copy;
}
template <class T>
const CSet<T> CSet<T>::INTERSECT(const CSet& set)//private
{
CSet copy;
copy.m_length = m_length;
copy.m_setArr = m_setArr;
for (int i = 0; i < set.m_length; i++)
copy.operator-=(set.m_setArr[i]);
return copy;
}
template <class T>
int CSet<T>::appears(const T& val)//private
{
for (int i = 0; i < m_length; i++)
if (m_setArr[i] == val)
return i;
return -1;
}
#endif
MENU//打印并显示集合菜单 H 文件
#ifndef __MENU_H__
#define __MENU_H__
#include"CSet.h"
#include <iostream>
using namespace std;
class Menu
{
public:
Menu();//prints menu
private:
//--members--//
CSet<long> longSet;
CSet<char> chSet1;
CSet<char> chSet2;
CSet<string> strSet;
//--methods--//
bool check();
void printSetsOp();
void addRemoveElement(bool);
void difference();
};
#endif
MENU.CPP
#include "Menu.h"
#include "CSet.h"
#include <iostream>
using namespace std;
Menu::Menu()
{//menu print
do {
//show the menu until the user wants to exit
cout << "================MENU================" << endl;
...
} while (check());//as long as the user doesnt want to exit
}
bool Menu::check()
{
int choice;
cin >> choice;//user input
switch (choice)
{
case 1:
{
...
return true;//keep the menu loop going
}
.
.
.
case 7:
{//exit
cout << "Goodbye!" << endl;
return false;//exit the program
}
default:
{//invalid number
cout << "please enter a valid number!" << endl;
return true;//keep the menu loop going
}
}
}
void Menu::printSetsOp()
{
//print options
}
void Menu::addRemoveElement(bool add)
{
printSetsOp();//print scnd menu
int choice;
cin >> choice;//which set
switch (choice)
{
case 1:
{//add or remove elements, each type seperatly
long elm;
cout << "Insert number = ";
cin >> elm;
add ? longSet.operator+=(elm) : longSet.operator-=(elm);
return;
}
case 2:
case 3:
{
char ch;
cout << "Insert character = ";
cin >> ch;
if (add)
(choice == 2) ? chSet1.operator+=(ch) : chSet2.operator+=(ch);
else
(choice == 2) ? chSet1.operator-=(ch) : chSet2.operator-=(ch);
return;
}
default:
{//invalid number
cout << "please enter a valid number!" << endl;
return;//keep the menu loop going
}
}
}
不知道是什么原因导致此错误,所以几乎所有内容都已发布。 谢谢
问题是您 CSet
的朋友 operator<<
命名的函数与您的模板 operator<<
不同。这实际上声明了一个新的 non-template 函数,它最终成为比模板函数更好的候选者,但是没有定义这样的函数,因此出现链接错误。
您可以通过使友元声明引用此运算符针对特定 CSet<T>
的完全特化来解决此问题。为此,必须已经声明模板函数,这需要 CSet
的前向声明。所以,你会做这样的事情:
template <class T> class CSet;
template <class T>
ostream& operator<<(ostream& os, const CSet<T>& set)
{
// implementation here
}
template <class T>
class CSet {
// all of your other stuff...
// Add <> to have the friend declaration refer to a specific operator<< instantiation
// With <>, T is deduced. You can also say <T> instead.
friend ostream& operator<< <>(ostream&, const CSet& );
};
请注意,当您在模板类型中声明非模板友元函数时,大多数编译器应该警告您,因为它会导致您遇到的问题。确保您的编译器警告已启用。
warning: friend declaration 'std::ostream& operator<<(std::ostream&, const foo<T>&)' declares a non-template function