如何使用 C++ 中的模板编程从基类创建派生类?
Posted
技术标签:
【中文标题】如何使用 C++ 中的模板编程从基类创建派生类?【英文标题】:How to create derived classes from a base class using template programming in C++? 【发布时间】:2010-12-13 11:51:08 【问题描述】:我需要从一个基类创建多个类(超过 50 个),唯一的区别在于派生类的名称。
例如,我的基类定义为:
class BaseError : public std::exception
private:
int osErrorCode;
const std::string errorMsg;
public:
int ec;
BaseError () : std::exception(), errorMsg()
BaseError (int errorCode, int osErrCode, const std::string& msg)
: std::exception(), errorMsg(msg)
ec = errorCode;
osErrorCode = osErrCode;
BaseError (const BaseError& other)
: std::exception(other), errorMsg(other.errorMsg)
ec = other.errorCode;
osErrorCode = other.osErrorCode;
const std::string& errorMessage() const return errorMsg;
virtual ~BaseError() throw()
我必须从这个基类创建很多派生类,每个派生类都有自己的构造函数、复制构造函数和虚拟析构函数,目前我正在复制/粘贴代码,在必要时更改名称:
class FileError : public BaseError
private:
const std::string error_msg;
public:
FileError () :BaseError(), error_msg()
FileError (int errorCode, int osErrorCode, const std::string& errorMessage)
:BaseError(errorCode, osErrorCode, errorMessage)
virtual ~FileError() throw()
;
问题: 有没有办法让这些类使用模板创建,这样就不会重复实现?
【问题讨论】:
稍微不相关的评论:与其提供自己的const std::string& errorMessage() const
getter,不如重新实现通过继承std::exception
获得的虚拟const char *std::exception::what() const
函数。
为什么需要派生类?一个简单的typedef
还不够吗?据我所知,派生类没有任何用处。
如果你的派生类的行为保持不变,那么为什么不去模板化类呢?
另一个远程相关的评论:如果您的所有异常(可以)都有消息,请考虑在您的基类中只拥有一个 std::string errorMsg;
成员,而不是在基类中拥有一个成员,然后每个派生类中拥有一个成员.这更有效(就内存和运行时速度而言)。您可以通过提供(受保护的)setter 或将参数传递给基类构造函数来设置字符串成员变量。
【参考方案1】:
我想你想创建一个类层次结构,这样你就可以在你的 catch 子句中使用动态调度(依靠编译器来找出正确的类型)来实现自定义错误处理。为此,您可以保持BaseError
类的原样,然后添加一个模板类,然后为其提供多个实例化。考虑一下:
class BaseError : public std::exception
private:
int osErrorCode;
const std::string errorMsg;
public:
int ec;
BaseError () : std::exception(), errorMsg()
BaseError (int errorCode, int osErrCode, const std::string& msg)
: std::exception(), errorMsg(msg)
ec = errorCode;
osErrorCode = osErrCode;
// ...
;
template <int T>
class ConcreteError : public BaseError
public:
ConcreteError () :BaseError(), error_msg()
ConcreteError (int errorCode, int osErrorCode, const std::string& errorMessage)
:BaseError(errorCode, osErrorCode, errorMessage)
;
您现在可以设置一些类型定义:
typedef ConcreteError<0> FileError;
typedef ConcreteError<1> NetworkError;
typedef ConcreteError<2> DatabaseError;
// ...
您现在有一个包含三个不同错误类别的层次结构。
【讨论】:
我喜欢这个,非常优雅(尤其是你以后总是给特定的例外他们自己的实现而不破坏这个方案)。唯一要补充的是,整数值应该是命名常量或枚举的一部分。 :) 这是否允许从共享库中抛出异常? @Mephane:在这种情况下,命名常量或枚举会给你什么?您只需要有不同的类 - 您永远不会通过 ID 引用它们,因此您不需要为 ID 命名。 好吧,您可以将枚举设为例如 FILE, NETWORK, DATABASE, ...
并将 ConcreteError
重命名为 Error
,并跳过 typedef 以支持仅使用例如Error<FILE>
。 :)
@Frerich Raabe:这确实是最优雅的解决方案。我只有一个问题,id 编号对于 typedef 来说应该是唯一的吗?或者,如果我对所有这些都使用相同的数字,会有什么不同吗?另外,非常感谢您详细查看我的代码。我一定会根据您的建议工作。【参考方案2】:
如果实现相同,则创建一个枚举,并在其上进行模板化。
enum error
file_error,
;
template<error e> class my_exception : public BaseError
....
;
typedef my_exception<file_error> file_exception;
【讨论】:
为什么要在这种情况下使用命名常量或枚举呢?您只需要有不同的类 - 您永远不会通过 ID 引用它们,因此您不需要 ID 的名称。你总是只使用 typedef。 @Frerich:能够通过枚举引用它们并没有错。这是此解决方案的额外优势。【参考方案3】:如果实现完全相同,并且您只想为每个类使用不同的名称,那么简单的 typedef 就可以完成您的工作。
如果在实现上存在细微差别,但不是在接口上,那么您可能需要模板。然后再考虑policy based design。
【讨论】:
以上是关于如何使用 C++ 中的模板编程从基类创建派生类?的主要内容,如果未能解决你的问题,请参考以下文章