【问题标题】:Condition in class constructor c++类构造函数c ++中的条件
【发布时间】:2018-08-28 12:46:14
【问题描述】:

我必须编写一个包含个人数据(例如姓名、姓氏和年龄)的类定义,条件是年龄不能小于 1。我试图在类构造函数中捕获一个异常:

class Person {

public:
    Person (std::string name, std::string surname, int age) {
        try{
            this -> name = name;
            this -> surname = surname;
            this -> age = age;

            if(age < 1)
                throw std::string("Error! Age cannot be less than 1!");
       }

       catch(std::string ex){
           cout << ex << endl;
       }
};

private:
    std::string name;
    std::string surname;
    int age;
};

这很好用,但最重要的是 根本不应该创建年龄 ,而使用此解决方案时,我只会收到错误,并且对象为 person1("Thomas ", "Something", -5) 仍在创建中。

“阻止”创建不满足条件的对象的最佳方法是什么?

【问题讨论】:

  • 不要捕获异常。一旦抛出异常就捕获它没有多大意义。
  • 如果您捕获到异常,该语言会假定您修复了错误。如果无法修复,请不要抓住并吞下它。
  • 捕获(而不是重新抛出)异常会告诉程序您处理了错误。异常不会自行传播。
  • 要明确一点,如果不捕获异常,就不会创建对象。
  • @GarrettGutierrez 1) “在我看来,在构造函数中引发异常通常是不明智的”您将如何处理由于某种原因无法创建对象的情况或其他?如果您无法使用它,为什么要创建一个处于无效状态的对象? 2)“不会调用析构函数,因为容器实际上并未完全构造。”是什么阻止您捕获异常、清理所有使用的资源并重新抛出异常?

标签: c++ class object constructor conditional-statements


【解决方案1】:

保证您不会创建具有错误值的对象的一种方法是在构造函数中抛出异常,就像您所做的那样。只是不要捕获它,让它被试图创建坏对象的代码捕获:

class Person
{
public:
    Person(std::string name, std::string surname, int age) {

        if(age < 1)
            throw std::string("Error! Age cannot be less than 1!");

        this->name = name;
        this->surname = surname;
        this->age = age;

    }

private:
    std::string name;
    std::string surname;
    int age;
};

顺便说一句,更常见的是使用构造函数的初始化列表来初始化变量:

class Person
{
public:
    Person(std::string const& name, std::string const& surname, int age)
    : name(name), surname(surname), age(age) {

        if(age < 1)
            throw std::runtime_error("Error! Age cannot be less than 1!");
    }

private:
    std::string name;
    std::string surname;
    int age;
};

通过在构造函数中抛出,可以保证对象在使用时是有效的:

int main()
{    
    try
    {
        Person p("John", "Doe", -5);

        // if we get here the person must be valid
    }
    catch(std::exception const& e)
    {
        std::cerr << e.what() << '\n';
        return EXIT_FAILURE;
    }
}

另外请注意,我抛出了一个std::exception 派生对象,而不是std::string,因为这更符合习惯和推荐。

【讨论】:

  • 考虑std::range_error,它派生自runtime_error。抛出std::exception 派生对象的一个​​简洁原因是异常对象的类型应该描述异常的类型。 “字符串”不会那样做。
  • @DrewDormann 我确实考虑过 range_error,但总的来说,我认为这可能更适合糟糕的索引值而不是狡猾的用户输入(可能是数字或文本)。
猜你喜欢
  • 1970-01-01
  • 2017-09-11
  • 2021-07-24
  • 1970-01-01
  • 2020-09-21
  • 2013-11-02
  • 2012-04-23
  • 2014-05-27
  • 1970-01-01
相关资源
最近更新 更多