【问题标题】:Calling the default constructor from another constructor从另一个构造函数调用默认构造函数
【发布时间】:2015-02-08 04:13:14
【问题描述】:

我试图让重载的构造函数调用默认构造函数,但它只给了我垃圾号。我想要它做的是识别输入的日期是否无效,因此将其默认为 2000 年 1 月 1 日。

#include <iostream>
#include <iomanip>
#include <string>
#include "date.h"

using namespace std;

Date::Date () 
{
        month = 1;
        day = 1;
        year = 2000;
        monthName = "Jan ";
        format = 'D';
        valid = true;
}

Date::Date (int m, int d, int y)
{   
    valid = false;

        if (y > 0)
        {
            //January
            if (m == 1 && d >= 1 && d <= 31)
            {
                month = m; day = d; year = y; 
                monthName = "Jan "; valid = true;
            }

            //February
            else if (m == 2 && d >= 1 && d <= 28)
            {
                month = m; day = d; year = y; 
                monthName = "Feb "; valid = true;
            }

            //etc.
        }

    if (valid == false)
        Date ();
}

【问题讨论】:

    标签: c++ constructor call


    【解决方案1】:

    只有在对象第一次被构造时才能调用构造函数。它不是通用函数。

    您的代码正在执行此操作 - 构造一个新的 Date,但没有对其执行任何操作。

    Date ();
    

    您可以通过分配新的、默认构造的Date 来实现您想要的。

    *this = Date(); 
    

    编辑:确保 valid 在这种情况下是您想要的。

    【讨论】:

    • 你是我的英雄,我爱你。
    • 投反对票,因为 (a) 这个答案设法将一个成员初始化为错误的值,并且 (b) 它使用了所有可能的非自然方法中最不干净的方法。
    • @Cheersandhth.-Alf (a) 我不够聪明,无法弄清楚那会是什么成员。我诚实地尝试过。 (b) 我会说它非常不干净,也是工作的最短路径。这不是“最不干净”,但我不会用例子让你痛苦,而且我相信你没有对这种直觉投反对票。
    • @DrewDormann:从 OP 的代码中不是很明显,但 valid 是一个数据成员。并且应该(没有现实的替代方案)大概表明 Date 对象是否代表有效参数。但是,默认构造函数将其设置为true
    • @Cheersandhth.-Alf 感谢您的澄清。我认为 valid 是一个成员,但不想推测它的正确用法。
    【解决方案2】:

    首先,在

    Date ();
    

    你正在构建一个临时的,并丢弃它。 C++ 确实具有在现有存储上调用构造函数的低级工具,但普通的构造函数调用只会创建一个新对象。

    还要注意

    if (valid == false)
    

    可以而且应该更简洁地表达为just

    if( not valid )
    

    或者如果你喜欢符号运算符,

    if( !valid )
    

    现在,可以表达原代码的意图

    • 通过转发到通用构造函数(一种自然的方式是调用并传递月份名称函数的结果),或者

    • 默认情况下——先构造后修改,或者

    • 通过分配一个默认构造的实例。

    按照从最干净到最不干净的顺序排列。

    请注意,分配一个默认构造的实例,上面最脏的选项,并且什么都不做,正如另一个答案中所建议的那样,会将valid 成员设置为true,从而删除有关以下事实的所有信息构造函数参数无效...

    但是,这些选项都不好!就意图而言,将参数错误视为默认请求的意图本身就非常不好。相反,当您检测到参数错误时,抛出异常或终止,以便客户端代码手头不会有可能意外的对象。

    例如,做

    if( not valid ) { throw std::runtime_error( "Date::<init>: invalid args" ); }
    

    有些人更喜欢使用std::logic_errorstd::range_error

    顺便说一句,使用 Visual C++ 强制包含 &lt;iso646.h&gt; 以获得对 C++ 关键字(不太准确,保留字)andornot 的支持。


    (不推荐!但最不脏的原始意图实现)通用构造方法示例:

    class Date
    {
    private:
        int     day_;
        int     month_;
        int     year_;
        string  month_name_;
        bool    is_valid_;
    
        Date( int month, int day, int year, const string& month_name );
    
    public:
        static
        auto month_name_for( int month, int day, int year )
            -> string;
    
        Date();
        Date( int month, int day, int year );
    };
    
    Date::Date( const int m, const int d, const int y, const string& month_name )
        : month_(         month_name == ""? 1     : m )
        , day_(           month_name == ""? 1     : d )
        , year_(          month_name == ""? 2000  : y )
        , month_name_(    month_name == ""? "Jan" : month_name )
        , is_valid_( month_name != "" )
    {}
    
    auto Date::month_name_for( const int m, const int d, const int y )
        -> string
    {
        if( y > 0 )
        {
            if( m == 1 && 1 <= d && d <= 31 )           { return "Jan "; }
            const int days_in_feb = 28;     // TODO: correct for leap year
            if( m == 2 && 1 <= d && d <= days_in_feb )  { return "Feb "; }
            if( m == 3 && 1 <= d && d <= 31 )           { return "Mar "; }
            //etc.
        }
        return "";
    }
    
    Date::Date ()
        : Date( 0, 0, 0, "" )
    {}
    
    Date::Date( const int m, const int d, const int y )
        : Date( m, d, y, month_name_for( m, d, y ) )
    {}
    

    确保对象有效的每个构造函数示例(推荐):

    class Date
    {
    private:
        int     day_;
        int     month_;
        int     year_;
    
    public:
        static
        auto month_name_for( int month )
            -> string;
        static
        auto is_valid( int month, int day, int year )
            -> bool;
    
        Date();
        Date( int month, int day, int year );
    };
    
    auto Date::month_name_for( const int m )
        -> string
    {
        static const string names[] = { "Jan", "Feb" };        // Etc.
        return (1 <= m && m <= 12? names[m-1] : "");
    }
    
    auto Date::is_valid( const int m, const int d, const int y )
        -> bool
    {
        if( y > 0 )
        {
            if( m == 1 && 1 <= d && d <= 31 )           { return true; }
            const int days_in_feb = 28;     // TODO: correct for leap year
            if( m == 2 && 1 <= d && d <= days_in_feb )  { return true; }
            if( m == 3 && 1 <= d && d <= 31 )           { return true; }
            //etc.
        }
        return false;
    }
    
    Date::Date ()
        : Date( 1, 1, 2000 )
    {}
    
    Date::Date( const int m, const int d, const int y )
        : month_( m ), day_( d ), year_( y )
    {
        if( not is_valid( m, d, y ) )
        {
            throw runtime_error( "Date::<init>: invalid arguments" );
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-03-24
      • 1970-01-01
      • 2016-06-29
      • 1970-01-01
      • 2013-03-13
      • 1970-01-01
      • 2010-12-15
      • 1970-01-01
      • 2014-03-12
      相关资源
      最近更新 更多