为具有私有枚举成员的 class 重载输出 (<<) 运算符
Overloading output (<<) operator for a class with private enum member
我很难为此 class 尝试重载我的 << 输出运算符。 class 有私人成员 - enum class
和 string
。我编写的代码编译并运行,但 << 运算符仅针对枚举 class 重载。
根据我的理解和阅读,我需要做这样的事情:
friend ostream& operator<<(ostream& os, CDirectory const& dir)
但我似乎无法实现它,在这一点上我真的没有想法。我想重载整个 class CDirectory
的运算符,而不仅仅是 enum class Filetype
,它是成员之一。这甚至可以做到吗?
class CDirectory {
string m_strDirectory;
enum class Filetype {
Archive, Hidden, ReadOnly, System, FileNotSupported
};
multimap <CFile, Filetype> m_DirectoryMap;
public:
/* overloading operator<< for the enum class Filetype */
friend ostream& operator<<(ostream& os, Filetype const type)
{
switch (type)
{
case Filetype::Archive:
os << "archive";
break;
case Filetype::Hidden:
os << "hidden";
break;
case Filetype::ReadOnly:
os << "read-only";
break;
case Filetype::System:
os << "system";
break;
case Filetype::FileNotSupported:
os << "not-supported";
break;
}
return os;
}
/* explicit constructor - reads data from a file and inserts pairs
of types pair <CFile, enum Filetype> in a multimap */
CDirectory (const string& n) {
fp.open (n, ios::in);
string dirName, fileName, fType;
int fileSize;
Filetype filetype;
fp >> dirName;
m_strDirectory = dirName;
while (fp >> fileName >> fileSize >> fType) {
CFile obj (fileName, fileSize);
if (fType == "Archive")
filetype = Filetype::Archive;
else if (fType == "Hidden")
filetype = Filetype::Hidden;
else if (fType == "ReadOnly")
filetype = Filetype::ReadOnly;
else if (fType == "System")
filetype = Filetype::System;
else
filetype = Filetype::FileNotSupported;
m_DirectoryMap.insert(pair<CFile, Filetype>(CFile(obj.getFileName(), obj.getFileSize()), Filetype(filetype)));
}
auto p = m_DirectoryMap.begin();
cout << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
void printMap () {
auto p = m_DirectoryMap.begin();
cout << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
};
更新:
我尝试了以下代码,为我的整个 class 实现重载运算符 <<,但它产生了一个错误 - error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'|
在这些行上(其中 1 个在我的构造函数中并且1 在我的 printMap 函数中)- cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p-
>second << endl;
我猜它与 p->second
部分有关,但我不知道到底发生了什么。有什么想法吗?
更新:是的,问题是当我尝试使用 p->second
打印枚举时。如果我删除它编译的那部分..
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
const Filetype& type;
switch (type)
{
case Filetype::Archive:
os << "archive";
break;
case Filetype::Hidden:
os << "hidden";
break;
case Filetype::ReadOnly:
os << "read-only";
break;
case Filetype::System:
os << "system";
break;
case Filetype::FileNotSupported:
os << "not-supported";
break;
}
os << dir.m_strDirectory << "\n";
for(auto &p : dir.m_DirectoryMap) {
os << p.first.getFileName() << '\t' << p.first.getFileSize() << '\t' << p.second << '\n';
}
return os;
}
我的印象是您混淆了 class 的数据成员和嵌套类型(成员类型)。运算符(将)定义为类型,而不是数据成员。
您必须为 每个 class/type 重载 operator<<
(用于流输出)已经定义。从你的代码来看,我认为你只需要重载
ostream& operator<<(ostream& os, Filetype const type)
你做到了。所以不清楚你的问题到底是什么,它的症状是什么。
在我看来你拥有你需要的一切,你只需要把它们放在一起。
printMap()
函数已经打印了 class CDirectory
中的所有内容。它将所有内容打印到 cout
。因此,您只需执行以下操作,它就会起作用。
friend ostream& operator<<(ostream& os, const CDirectory& dir)
{
dir.printMap();
}
但是这段代码写得不好,因为 opeartor<<
更通用,而不仅仅是为 cout
编写的。为了使它更好,您可以重写 printMap() 函数以引用要输出到的 ostream
。
void printMap (ostream& os)
{
os << m_strDirectory << endl;
auto p = m_DirectoryMap.begin();
while ( p != m_DirectoryMap.end())
{
os << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
void printMap () { printMap(std::cout); }
现在运算符看起来像这样:
friend ostream& operator<<(ostream& os, const CDirectory& dir)
{
dir.printMap(os);
}
我希望这能更好地解释发生了什么。
我假设你最终希望能够做这样的事情:
CDirectory dir("input_file");
std::cout << dir;
这应该会立即输出所有内容(基本上 CDirectory::printMap()
当前打印的所有内容,对吗?
为此,您需要为 CDirectory
class 重载 operator<<
作为非成员函数:
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
os << dir.m_strDirectory << "\n";
for(auto &p : dir.m_DirectoryMap) {
std::cout << p.first.getFileName() << '\t' << p.first.getFileSize() << '\t' << p.second << '\n';
}
return os;
}
然后让这个函数成为你的朋友 class:
friend std::ostream& operator<<(std::ostream &os, const CDirectory &dir);
使其能够访问 class 的私有成员。
或者,因为您的 class 中已经有一个打印功能,您可以转发到那个功能,这样您就不需要与 operator<<
成为朋友(有些人不喜欢朋友职能)。为此,您必须稍微更改 printMap()
函数:
void printMap (std::ostream &os) const
{
auto p = m_DirectoryMap.begin();
os << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
os << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
dir.printMap();
return os;
}
一旦你有了这个运算符,用两种变体中的任何一种编写,在你的 main()
函数中你可以写:
CDirectory dir("input_file");
std::cout << dir;
关于您已经为 Filetype
重载的运算符的两个注释。它是唯一需要为您的 class 重载的其他运算符才能流式传输(operator<<
已经为 std::string
和整数类型重载,因此您不必这样做能够写字符串和数字)。还要记住,即使你把它写在你的 class 中,它实际上不是一个成员函数,也不能是一个成员函数(为什么?)。您可以在那里定义它,因为您声明了它 friend
,但是通常定义友元函数的方式是这样的:
class A {
...
friend void f();
...
};
void f() {
...
}
我很难为此 class 尝试重载我的 << 输出运算符。 class 有私人成员 - enum class
和 string
。我编写的代码编译并运行,但 << 运算符仅针对枚举 class 重载。
根据我的理解和阅读,我需要做这样的事情:
friend ostream& operator<<(ostream& os, CDirectory const& dir)
但我似乎无法实现它,在这一点上我真的没有想法。我想重载整个 class CDirectory
的运算符,而不仅仅是 enum class Filetype
,它是成员之一。这甚至可以做到吗?
class CDirectory {
string m_strDirectory;
enum class Filetype {
Archive, Hidden, ReadOnly, System, FileNotSupported
};
multimap <CFile, Filetype> m_DirectoryMap;
public:
/* overloading operator<< for the enum class Filetype */
friend ostream& operator<<(ostream& os, Filetype const type)
{
switch (type)
{
case Filetype::Archive:
os << "archive";
break;
case Filetype::Hidden:
os << "hidden";
break;
case Filetype::ReadOnly:
os << "read-only";
break;
case Filetype::System:
os << "system";
break;
case Filetype::FileNotSupported:
os << "not-supported";
break;
}
return os;
}
/* explicit constructor - reads data from a file and inserts pairs
of types pair <CFile, enum Filetype> in a multimap */
CDirectory (const string& n) {
fp.open (n, ios::in);
string dirName, fileName, fType;
int fileSize;
Filetype filetype;
fp >> dirName;
m_strDirectory = dirName;
while (fp >> fileName >> fileSize >> fType) {
CFile obj (fileName, fileSize);
if (fType == "Archive")
filetype = Filetype::Archive;
else if (fType == "Hidden")
filetype = Filetype::Hidden;
else if (fType == "ReadOnly")
filetype = Filetype::ReadOnly;
else if (fType == "System")
filetype = Filetype::System;
else
filetype = Filetype::FileNotSupported;
m_DirectoryMap.insert(pair<CFile, Filetype>(CFile(obj.getFileName(), obj.getFileSize()), Filetype(filetype)));
}
auto p = m_DirectoryMap.begin();
cout << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
void printMap () {
auto p = m_DirectoryMap.begin();
cout << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
};
更新:
我尝试了以下代码,为我的整个 class 实现重载运算符 <<,但它产生了一个错误 - error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'|
在这些行上(其中 1 个在我的构造函数中并且1 在我的 printMap 函数中)- cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p-
>second << endl;
我猜它与 p->second
部分有关,但我不知道到底发生了什么。有什么想法吗?
更新:是的,问题是当我尝试使用 p->second
打印枚举时。如果我删除它编译的那部分..
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
const Filetype& type;
switch (type)
{
case Filetype::Archive:
os << "archive";
break;
case Filetype::Hidden:
os << "hidden";
break;
case Filetype::ReadOnly:
os << "read-only";
break;
case Filetype::System:
os << "system";
break;
case Filetype::FileNotSupported:
os << "not-supported";
break;
}
os << dir.m_strDirectory << "\n";
for(auto &p : dir.m_DirectoryMap) {
os << p.first.getFileName() << '\t' << p.first.getFileSize() << '\t' << p.second << '\n';
}
return os;
}
我的印象是您混淆了 class 的数据成员和嵌套类型(成员类型)。运算符(将)定义为类型,而不是数据成员。
您必须为 每个 class/type 重载 operator<<
(用于流输出)已经定义。从你的代码来看,我认为你只需要重载
ostream& operator<<(ostream& os, Filetype const type)
你做到了。所以不清楚你的问题到底是什么,它的症状是什么。
在我看来你拥有你需要的一切,你只需要把它们放在一起。
printMap()
函数已经打印了 class CDirectory
中的所有内容。它将所有内容打印到 cout
。因此,您只需执行以下操作,它就会起作用。
friend ostream& operator<<(ostream& os, const CDirectory& dir)
{
dir.printMap();
}
但是这段代码写得不好,因为 opeartor<<
更通用,而不仅仅是为 cout
编写的。为了使它更好,您可以重写 printMap() 函数以引用要输出到的 ostream
。
void printMap (ostream& os)
{
os << m_strDirectory << endl;
auto p = m_DirectoryMap.begin();
while ( p != m_DirectoryMap.end())
{
os << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
void printMap () { printMap(std::cout); }
现在运算符看起来像这样:
friend ostream& operator<<(ostream& os, const CDirectory& dir)
{
dir.printMap(os);
}
我希望这能更好地解释发生了什么。
我假设你最终希望能够做这样的事情:
CDirectory dir("input_file");
std::cout << dir;
这应该会立即输出所有内容(基本上 CDirectory::printMap()
当前打印的所有内容,对吗?
为此,您需要为 CDirectory
class 重载 operator<<
作为非成员函数:
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
os << dir.m_strDirectory << "\n";
for(auto &p : dir.m_DirectoryMap) {
std::cout << p.first.getFileName() << '\t' << p.first.getFileSize() << '\t' << p.second << '\n';
}
return os;
}
然后让这个函数成为你的朋友 class:
friend std::ostream& operator<<(std::ostream &os, const CDirectory &dir);
使其能够访问 class 的私有成员。
或者,因为您的 class 中已经有一个打印功能,您可以转发到那个功能,这样您就不需要与 operator<<
成为朋友(有些人不喜欢朋友职能)。为此,您必须稍微更改 printMap()
函数:
void printMap (std::ostream &os) const
{
auto p = m_DirectoryMap.begin();
os << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
os << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
dir.printMap();
return os;
}
一旦你有了这个运算符,用两种变体中的任何一种编写,在你的 main()
函数中你可以写:
CDirectory dir("input_file");
std::cout << dir;
关于您已经为 Filetype
重载的运算符的两个注释。它是唯一需要为您的 class 重载的其他运算符才能流式传输(operator<<
已经为 std::string
和整数类型重载,因此您不必这样做能够写字符串和数字)。还要记住,即使你把它写在你的 class 中,它实际上不是一个成员函数,也不能是一个成员函数(为什么?)。您可以在那里定义它,因为您声明了它 friend
,但是通常定义友元函数的方式是这样的:
class A {
...
friend void f();
...
};
void f() {
...
}