将自定义异常 类 放在哪里?
Where to put the custom exception classes?
假设我有一个class,你可以在下面看到(也请阅读评论):
Foo.h
#pragma once
namespace Bar
{
class Foo
{
public:
inline Foo( );
private:
char c;
inline static const std::unordered_set<char> CHAR_SET {'/', '\', '|', '-'};
friend class Invalid_C_Exception;
};
} // end of namespace Bar
我有:
Foo.cpp
#include "Foo.h"
using namespace Bar;
inline Foo::Foo( )
{
}
class Invalid_C_Exception : public std::exception
{
public:
virtual const char* what( ) const throw( )
{
std::stringstream ss;
ss << "Invalid_C_Exception: { ";
// compiler gives an error here because of usages of CHAR_SET
for ( auto it = Foo::CHAR_SET.cbegin( ); it != Foo::CHAR_SET.cend( ); ++it )
{
ss << "'" << *it << "', ";
}
return somehow_save_the_C_string(ss.str());
}
} Invalid_C_Exc;
第一个问题:
全局Invalid_C_Exc
变量是否存在?
第二题:
为什么编译器在尝试编译 Foo.cpp
时指责我 CHAR_SET
是私有的?
自定义异常 class,尽管是 class Foo
的朋友,但无法访问 CHAR_SET
?
第三题:
我应该把这些自定义异常 class 放在哪里?在单独的头文件和源文件中,但在相同的命名空间下?
我犹豫不决,所以我把声明和实现放在源文件中 Foo.cpp
因为异常 class 是为 class Foo
设计的,所以它们是相互关联的。
两者有很大区别
friend class Invalid_C_Exception;
和
friend Invalid_C_Exception;
后者期望 Invalid_C_Exception
已经存在 可访问的某个地方 并使该符号成为 Foo
的友元。前者在封闭范围 中声明了一个新符号 Invalid_C_Exception
并使其成为新朋友。
意味着你已经让 Bar::Invalid_C_Exception
成为 Foo
的朋友,而不是你稍后定义的全局 ::Invalid_C_Exception
仍然不是朋友。 Bar::Invalid_C_Exception
永远不会存在的事实无关紧要。
关于你的第一个问题,Invalid_C_Exc
是一个全局变量,默认有外部链接。如果您仅在该翻译单元(.cpp 文件)中使用它,请将其设为 static
或将其放入匿名命名空间。
我建议不要偷懒,把它的定义写在单独的一行上,这样会更清楚。除此之外,你可以很好地使用它,它在 main
开始之前初始化并一直存在到程序结束。
关于你的第三个问题。无论你想要什么,我通常会建议每个异常类型一个 .hpp
或它们的紧密组合。将其放入 .cpp
中很难捕捉到它。
1st question: Is the existence of this variable ok?
全局变量通常不是一个好主意,并且由于异常 objects 在抛出时被复制到专用的异常存储中,我看不出这个特定的全局变量有任何用处。
second question is that why does the compiler blame me for CHAR_SET being private
你定义一个classBar::Foo
并且声明它的朋友classBar::Invalid_C_Exception
... 但是您根本没有触及实现文件中的那些。您刚刚在全局命名空间中声明了一个新的 和无关的 Invalid_C_Exception
。
删除 using namespace Bar
并将 namespace Bar { ... }
中包含项下方的所有内容包装起来,与 header 中的相同。或者,如果您愿意,可以在任何地方显式地写 Bar::Foo
和 Bar::Invalid_C_Exception
。
using namespace
指令使命名空间 from 在封闭范围内可见。它不会将之后添加到封闭范围的所有内容 back 吸入命名空间。如果您有多个 using namespace
指令,那将如何工作?为什么 using namespace std;
会被允许?
3rd question: Where should I put these custom exception classes?
嗯,如果您希望任何人都能够使用它,则不能将定义放在您的实现文件中。把class的定义放在header里就行了,实现文件里只留下Bar::Invalid_C_Exception::what
的定义。
他们是否进入相同 header & 实施文件作为他们的 class 朋友取决于你,它不是真的很重要。
4th question: how many questions should I ask per question?
一个。这叫问题,不是问卷。
假设我有一个class,你可以在下面看到(也请阅读评论):
Foo.h
#pragma once
namespace Bar
{
class Foo
{
public:
inline Foo( );
private:
char c;
inline static const std::unordered_set<char> CHAR_SET {'/', '\', '|', '-'};
friend class Invalid_C_Exception;
};
} // end of namespace Bar
我有:
Foo.cpp
#include "Foo.h"
using namespace Bar;
inline Foo::Foo( )
{
}
class Invalid_C_Exception : public std::exception
{
public:
virtual const char* what( ) const throw( )
{
std::stringstream ss;
ss << "Invalid_C_Exception: { ";
// compiler gives an error here because of usages of CHAR_SET
for ( auto it = Foo::CHAR_SET.cbegin( ); it != Foo::CHAR_SET.cend( ); ++it )
{
ss << "'" << *it << "', ";
}
return somehow_save_the_C_string(ss.str());
}
} Invalid_C_Exc;
第一个问题:
全局Invalid_C_Exc
变量是否存在?
第二题:
为什么编译器在尝试编译 Foo.cpp
时指责我 CHAR_SET
是私有的?
自定义异常 class,尽管是 class Foo
的朋友,但无法访问 CHAR_SET
?
第三题:
我应该把这些自定义异常 class 放在哪里?在单独的头文件和源文件中,但在相同的命名空间下?
我犹豫不决,所以我把声明和实现放在源文件中 Foo.cpp
因为异常 class 是为 class Foo
设计的,所以它们是相互关联的。
两者有很大区别
friend class Invalid_C_Exception;
和
friend Invalid_C_Exception;
后者期望 Invalid_C_Exception
已经存在 可访问的某个地方 并使该符号成为 Foo
的友元。前者在封闭范围 中声明了一个新符号 Invalid_C_Exception
并使其成为新朋友。
意味着你已经让 Bar::Invalid_C_Exception
成为 Foo
的朋友,而不是你稍后定义的全局 ::Invalid_C_Exception
仍然不是朋友。 Bar::Invalid_C_Exception
永远不会存在的事实无关紧要。
关于你的第一个问题,Invalid_C_Exc
是一个全局变量,默认有外部链接。如果您仅在该翻译单元(.cpp 文件)中使用它,请将其设为 static
或将其放入匿名命名空间。
我建议不要偷懒,把它的定义写在单独的一行上,这样会更清楚。除此之外,你可以很好地使用它,它在 main
开始之前初始化并一直存在到程序结束。
关于你的第三个问题。无论你想要什么,我通常会建议每个异常类型一个 .hpp
或它们的紧密组合。将其放入 .cpp
中很难捕捉到它。
1st question: Is the existence of this variable ok?
全局变量通常不是一个好主意,并且由于异常 objects 在抛出时被复制到专用的异常存储中,我看不出这个特定的全局变量有任何用处。
second question is that why does the compiler blame me for CHAR_SET being private
你定义一个classBar::Foo
并且声明它的朋友classBar::Invalid_C_Exception
... 但是您根本没有触及实现文件中的那些。您刚刚在全局命名空间中声明了一个新的 和无关的 Invalid_C_Exception
。
删除 using namespace Bar
并将 namespace Bar { ... }
中包含项下方的所有内容包装起来,与 header 中的相同。或者,如果您愿意,可以在任何地方显式地写 Bar::Foo
和 Bar::Invalid_C_Exception
。
using namespace
指令使命名空间 from 在封闭范围内可见。它不会将之后添加到封闭范围的所有内容 back 吸入命名空间。如果您有多个 using namespace
指令,那将如何工作?为什么 using namespace std;
会被允许?
3rd question: Where should I put these custom exception classes?
嗯,如果您希望任何人都能够使用它,则不能将定义放在您的实现文件中。把class的定义放在header里就行了,实现文件里只留下Bar::Invalid_C_Exception::what
的定义。
他们是否进入相同 header & 实施文件作为他们的 class 朋友取决于你,它不是真的很重要。
4th question: how many questions should I ask per question?
一个。这叫问题,不是问卷。