Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模糊虚固有_C++_C++11_C++14 - Fatal编程技术网

C++ 模糊虚固有

C++ 模糊虚固有,c++,c++11,c++14,C++,C++11,C++14,对于应用程序,我需要创建一组特殊类来处理异常。我从std::exception派生了我的基类。然而,我最终面临钻石问题和模棱两可的继承。即使使用虚拟继承也没有帮助。下面的示例演示了该问题 #include <iostream> class Exception: public virtual std::exception { public: Exception(): std::exception("This is default") {

对于应用程序,我需要创建一组特殊类来处理异常。我从std::exception派生了我的基类。然而,我最终面临钻石问题和模棱两可的继承。即使使用虚拟继承也没有帮助。下面的示例演示了该问题

#include <iostream>

class Exception:
    public virtual std::exception
{
public:
    Exception():
        std::exception("This is default")
    {        
        std::cout << "This is Exception\n";
    } 
};

class ChildException:
    public virtual std::runtime_error,
    public Exception

{
public:
    ChildException():
        Exception(),
        std::runtime_error("hello")
    {
        std::cout << "This is ChildException\n";
    }
};
int main() 
{
    ChildException exc();    
    //std::cout << static_cast<std::exception> (exc).what() << std::endl;
    //std::cout << static_cast<std::runtime_error> (exc).what() << std::endl;    
    getchar();
    return 0;
}
#包括
类异常:
公共虚拟std::异常
{
公众:
异常():
std::exception(“这是默认值”)
{        

std::cout目前我可以看到两个问题:


1:最烦人的解析 正如评论中所指出的,这一行实际上是一个函数原型:

ChildException exc();

它可以被读取为“<代码> CyrExcExpTo> <代码>命名为代码> EXC/<代码>,它是通过调用默认构造函数初始化的,或者作为一个名为“代码> EXC/<代码>的函数返回一个<代码> CyrExcRebug ;我不确定确切的原因,但是C++标准规定,在这种情况下,它将被读取为后者。< /P> 有三种方法可以解决这个问题:

  • 删除括号:如果您只是调用默认构造函数,则可以不使用括号直接编写。然而,这并不总是一个选项,因为当您尝试使用通过函数调用获得的值进行直接初始化时,最麻烦的解析也会让您措手不及

    ChildException exc;
    
    // Most vexing parse:
    ChildException ce;
    
    ChildException ce2(ce);
      // This is safe, it can't be read as a function prototype.
    ChildException ce3(ChildException());
      // This will be parsed as a function with:
        // Return type: ChildException
        // Parameter: Function pointer of type "ChildException (*)()".
    
  • 使用复制初始化:您可以使用赋值语法对其进行初始化,编译器将通过复制省略对其进行优化

    ChildException exc = ChildException();
    
    这是可行的,但看起来不必要的笨拙,如果遇到无法执行复制省略的编译器,则可能会降低效率

  • ChildException exc = ChildException();
    
  • 使用统一初始化:从C++11开始,当使用支持统一初始化*的编译器时,可以使用大括号而不是括号来指定构造函数调用;考虑到问题的标记,我建议使用这种方法

    ChildException exc{};
    
    *[在三个“最大”中编译器,Clang 3.1或更高版本、GCC 4.6或更高版本以及Visual Studio 2013或更高版本支持统一初始化。虽然GCC从4.4开始支持统一初始化,而Visual Studio从2012 CTP开始支持统一初始化,但早期版本在某些情况下遇到了困难;我不确定Clang的早期版本是否存在问题。]


2:钻石问题 我假设您遇到问题的代码是两行注释:

//std::cout << static_cast<std::exception> (exc).what() << std::endl;
//std::cout << static_cast<std::runtime_error> (exc).what() << std::endl;
请注意,如果您愿意,虽然您的
异常
实际上继承自
std::Exception
std::runtime\u error
。因此,它的
std::Exception
基与您的
Exception
基不同,因此任何将
ChildException
强制转换为
std::exception
将是不明确的,因为它可能引用
ChildException::exception
基或
ChildException::runtime\u error::exception
基。如果可能,我建议重构您的异常类,使每个异常类最多继承一个
std
异常类。I如果不可能,可以通过基类之一强制转换:

// Cast into std::exception through the base classes:
std::cout << "As Exception: "
          << static_cast<std::exception>(static_cast<Exception>(exc)).what()
          << std::endl;

std::cout << "As runtime_error: "
          << static_cast<std::exception>(static_cast<std::runtime_error>(exc)).what()
          << std::endl;
//通过基类强制转换为std::exception:

std::cout目前我可以看到两个问题:


1:最烦人的解析 正如评论中指出的,这一行实际上是一个功能原型:

ChildException exc();

它可以被读取为“<代码> CyrExcExpTo> <代码>命名为代码> EXC/<代码>,它是通过调用默认构造函数初始化的,或者作为一个名为“代码> EXC/<代码>的函数返回一个<代码> CyrExcRebug ;我不确定确切的原因,但是C++标准规定,在这种情况下,它将被读取为后者。< /P> 有三种方法可以解决这个问题:

  • 删除括号:如果您只是调用默认构造函数,则可以不使用括号直接编写。然而,这并不总是一个选项,因为当您尝试使用通过函数调用获得的值进行直接初始化时,最麻烦的解析也会让您措手不及

    ChildException exc;
    
    // Most vexing parse:
    ChildException ce;
    
    ChildException ce2(ce);
      // This is safe, it can't be read as a function prototype.
    ChildException ce3(ChildException());
      // This will be parsed as a function with:
        // Return type: ChildException
        // Parameter: Function pointer of type "ChildException (*)()".
    
  • 使用复制初始化:您可以使用赋值语法对其进行初始化,编译器将通过复制省略对其进行优化

    ChildException exc = ChildException();
    
    这是可行的,但看起来不必要的笨拙,如果遇到无法执行复制省略的编译器,则可能会降低效率

  • ChildException exc = ChildException();
    
  • 使用统一初始化:从C++11开始,当使用支持统一初始化*的编译器时,可以使用大括号而不是括号来指定构造函数调用;考虑到问题的标记,我建议使用这种方法

    ChildException exc{};
    
    *[在三个“最大”中编译器,Clang 3.1或更高版本、GCC 4.6或更高版本以及Visual Studio 2013或更高版本支持统一初始化。虽然GCC从4.4开始支持统一初始化,而Visual Studio从2012 CTP开始支持统一初始化,但早期版本在某些情况下遇到了困难;我不确定Clang的早期版本是否存在问题。]


2:钻石问题 我假设您遇到问题的代码是两行注释:

//std::cout << static_cast<std::exception> (exc).what() << std::endl;
//std::cout << static_cast<std::runtime_error> (exc).what() << std::endl;
请注意,如果您愿意,虽然您的
异常
实际上继承自
std::Exception
std::runtime\u error
。因此,它的
std::Exception
基与您的
Exception
基不同,因此任何将
ChildException
强制转换为
std::exception
将是不明确的,因为它可能引用
ChildException::exception
基或
ChildException::runtime\u error::exception
基。如果可能,我建议重构您的异常类,使每个异常类最多继承一个
std
异常类。I如果不可能,可以通过基类之一强制转换:

// Cast into std::exception through the base classes:
std::cout << "As Exception: "
          << static_cast<std::exception>(static_cast<Exception>(exc)).what()
          << std::endl;

std::cout << "As runtime_error: "
          << static_cast<std::exception>(static_cast<std::runtime_error>(exc)).what()
          << std::endl;
//通过基类强制转换为std::exception:
圣