【问题标题】:C++ declare exception in hpp fileC++ 在 hpp 文件中声明异常
【发布时间】:2017-01-18 18:45:02
【问题描述】:

我想修改PierreBdR's exception example 如何制作自定义异常,使其对其他类可见。他的示例对我有用,但异常仅在该类中可见。

我正在使用 MS Visual Studio 2013,我是一名 C++ 新手,受 Java 思维的束缚。

这是 .hpp 文件中的内容:


struct IllegalArgumentException : public std::exception
{
public: IllegalArgumentException(std::string ss);
public: ~IllegalArgumentException();

const char* IllegalArgumentException::what()  { return s.c_str(); }

private: std::string s;

};

这是 .cpp 文件的一部分:

IllegalArgumentException::IllegalArgumentException(std::string ss) : s(ss) {} IllegalArgumentException::~IllegalArgumentException() {} const char * IllegalArgumentException::what() { return s.c_str(); }

我明白了:

  • 错误 C2011:“IllegalArgumentExcpetion”:“struct”类型重新定义(.hpp 文件)

【问题讨论】:

  • 一方面,cpp 文件中的what() 应该是IllegalArgumentException::what()
  • @0x5453,谢谢。代码修改,只剩一个错误。
  • 您忘记了标题周围的包含防护。

标签: c++ visual-c++


【解决方案1】:

第 1 点

const char* IllegalArgumentException::what()  { return s.c_str(); }

如果在classstruct 中声明,则声明不正确。由于声明是在 IllegalArgumentException 类中进行的,IllegalArgumentException:: is implied 并与编译器混淆,因为编译器现在认为您正在声明其他内容。你想要

const char* what()  { return s.c_str(); }

另外,{ return s.c_str(); }部分实现了该功能,所以不需要在cpp文件中实现。

第 2 点

struct 中的所有内容都是 public,除非在 private 关键字之后声明。这与class 相反,除非另有说明,否则一切都是privateclassstruct 除了默认访问权限不同外几乎完全相同。

第 3 点

在 C++ 中,您可以在块中声明成员的访问级别。无需一次声明一个成员的访问级别。

struct IllegalArgumentException : public std::exception 
{ 
    // these are all public by default in a struct
    IllegalArgumentException(std::string ss); 
   ~IllegalArgumentException(); 
    const char* IllegalArgumentException::what() { return s.c_str(); } 
private: // everything after this is private
    std::string s; 
    int example; 
}; 

class IllegalArgumentException : public std::exception 
{ 
public: // these are all private by default in a class and need to be public
    IllegalArgumentException(std::string ss); 
   ~IllegalArgumentException(); 
    const char* IllegalArgumentException::what() { return s.c_str(); }
private: // switch back to private
    std::string s; 
    int example; 
}; 

class IllegalArgumentException : public std::exception 
{ 
    // these are all private by default in a class
    std::string s; 
    int example; 
public: // everything after this is public
    IllegalArgumentException(std::string ss); 
   ~IllegalArgumentException(); 
    const char* IllegalArgumentException::what() { return s.c_str(); }
}; 

第 4 点

IllegalArgumentException::~IllegalArgumentException() {}

什么都不做。它不需要做任何事情,所以Rule of Zero 建议完全不要使用析构函数。编译器将为您创建它。不用写就别写,因为不存在的代码没有bug。

class IllegalArgumentException : public std::exception 
{ 
    // these are all private by default 
    std::string s; 
    int example; 
public: // everything after this is public
    IllegalArgumentException(std::string ss); 
    const char* IllegalArgumentException::what() { return s.c_str(); }
}; 

第 5 点

这里从 KerrekSB 窃取,因为这是 OP 的另一个问题。 Use Include Guards

包含守卫可防止标头多次包含在同一个translation unit 中。这是一个问题,因为臃肿而且同一事物被多次定义或声明的可能性会导致混淆哪个是真实的。

一个简单的头部保护:

#ifndef ILLEGALARGUMENTEXCEPTION_H // if we've never seen ILLEGALARGUMENTEXCEPTION_H 
                                   // before, do the following
#define ILLEGALARGUMENTEXCEPTION_H // OK we've seen it now!

// all subsequent includes of IllegalArgumentException.h will have seen 
// ILLEGALARGUMENTEXCEPTION_H and fail the ifndef, skipping everything 
// until it finds the closing #endif

#include <string>
#include <exception>
class IllegalArgumentException : public std::exception 
{ 
    // these are all private by default 
    std::string s; 
    int example; 
public: // everything after this is public
    IllegalArgumentException(std::string ss); 
    const char* IllegalArgumentException::what() { return s.c_str(); }
}; 

#endif // end of Include Guard

您也可以使用#pragma once,但请注意#pragma 表示非标准编译器扩展。 once 可能不存在于您的编译器中,如果不存在,则允许编译器跳过指令不告诉您!

once不在标准中有很多原因,最重要的是它有unresolved fail cases。谨慎使用。

【讨论】:

  • 非常感谢你给了我这些好建议(我已经重读了好几遍)。但我必须奖励 czimbortibor 的答案,因为他的答案更符合极简主义和可验证的理想。
  • @ssimm 没问题。与问题直接相关的唯一一点是第 1 点,czimbortibor 对其进行了更详细的解释。
【解决方案2】:

您混淆了what() 函数的声明和定义。您尝试使用 scope resolution 运算符(即 ::)引用该函数。在这种情况下,它应该在定义中完成(即在 .cpp 文件中)

此外,what() 函数在您的 .hpp 文件中作为 内联 函数实现,这意味着您无需在 中再次定义它em>.cpp 文件。因此你得到一个redefinition of ‘const char* IllegalArgumentException::what() 错误。

P.S:在 C++ 类声明中,不需要指定每个属性/方法的访问修饰符,您可以将它们分组在一个修饰符下。

.hpp 文件:

struct IllegalArgumentException : public std::exception
{
public: 
 IllegalArgumentException(std::string ss);
~IllegalArgumentException();

const char* what()  { return s.c_str(); }

private: 
 std::string s;

};

.cpp 文件:

IllegalArgumentException::IllegalArgumentException(std::string ss) : s(ss) {}

IllegalArgumentException::~IllegalArgumentException() {}

【讨论】:

    【解决方案3】:

    您似乎可能(也许是间接地)不止一次地包含了 .hpp 文件?

    #include 是在多个 .cpp 文件之间共享代码的一种相当原始的方式:它告诉编译器(特别是预处理器)在代码中的那个位置导入 .hpp 的内容。然后在稍后的传递中,编译器将编译整个东西,就好像它是一个文件一样。 (对于该预处理步骤,有一整套疯狂的图灵完备语言;IMO 您应该尽可能避免使用它,主要只将它用于本说明中概述的内容。)

    这种方法的一个问题是,如果您最终多次导入一个 .hpp 文件 - 这是很常见的做法,因为 .hpp 文件通常包含其他 .hpp 文件 - 您将重复该代码。多次定义结构或类是非法的,因此您会收到有关“类型重新定义”的错误。

    解决方案是在每个 .hpp 文件中使用包含保护。在最顶部,使用如下行:

    #ifndef SOME_STRING_THAT_UNIQUELY_IDENTIFIES_THIS_HEADER
    #define SOME_STRING_THAT_UNIQUELY_IDENTIFIES_THIS_HEADER
    

    然后在.hpp文件的最底部:

    #endif  // SOME_STRING_THAT_UNIQUELY_IDENTIFIES_THIS_HEADER
    

    如果已经定义了大的唯一字符串,那些预处理器指令#ifndef#define 等将删除中间的任何文本。通常,您的代码库将为该大字符串建立约定,例如将路径编码到其中。我的公司甚至使用 lint 工具来确保您正确编码。

    这可确保如果您 #include 一个 .hpp 两次,或 #include 另一个包含已包含的 .hpp 的 .hpp,您将在最终预处理器输出中仅获得一次 .hpp 文件的内容。

    这和一般的预处理器一样,是 C++ 中不太吸引人的部分之一,它确实显示了它的时代。很快,该语言将获得一个更现代、更令人愉快的共享接口系统,称为“模块”。同时,每个 .hpp 都需要这 3 行样板文件。

    【讨论】:

    • ht。 Kerrek SB 和其他推断失踪的人包括警卫。
    【解决方案4】:

    我不确定,但我可以评论...

    我认为您的“什么”功能被实施了两次: 首先在您的 hpp 文件中,然后在 cpp 文件中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-28
      • 2022-01-24
      • 2014-08-02
      • 1970-01-01
      • 2023-04-09
      相关资源
      最近更新 更多