从另一个构造函数调用默认构造函数
问题描述:
我想让重载的构造函数调用默认的构造函数,但它只给了我垃圾数。我想要它做的是确认输入的日期是否无效,因此默认为1/1/2000。从另一个构造函数调用默认构造函数
#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();
}
答
一个构造当对象是第一次被构造只能被调用。这不是一个通用功能。
你的代码是这样做的 - 构建一个新的Date
,但不做任何事情。
Date();
你可以达到你想要分配新,默认构造Date
什么。
*this = Date();
编辑:确保valid
是你希望它是在这种情况下什么。
答
首先,在
Date();
你正在建设一个临时的,并丢弃它。 C++确实有低层次的设施来调用现有存储上的构造函数,但普通的构造函数调用只是创建一个新对象。
还要注意的是
if (valid == false)
可以而且应该更加清洁表述为刚刚
if(not valid)
,或者如果你喜欢象征性的运营商,
if(!valid)
现在,意图的原始代码可以表示为
通过转发到一个公共的构造(一种自然的方式将是通过调用并通过一个月份名称函数的结果),或
默认-构建第一和然后修改或
通过分配默认构造的实例。
这些是为了最干净的大多数不洁。
请注意,分配默认构造的情况下,上述最脏的选项,并做而已,在另一个答案建议,将valid
成员设置为true
,从而消除对事实的所有信息,构造函数参数无效&hellip;
但是,这些选项都不是好的!对于意图来说,将参数错误当作默认请求来处理,本身就非常不合适。相反,当您检测到参数错误时,抛出异常或终止,以便客户端代码不会有可能意外的对象。
例如,做
if(not valid) { throw std::runtime_error("Date::<init>: invalid args"); }
有些人喜欢使用std::logic_error
或std::range_error
。
顺带一提,用Visual C++力包括<iso646.h>
得到支撑的C++的关键字(以下不精确,保留字)and
,or
和not
。 (不推荐,但至少脏原意实现!)的
实施例共同的构造的方法:每个构造确保有效目标的
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");
}
}
你是我的英雄,我爱你。 – JMoore 2015-02-08 04:18:09
Downvote因为(a)这个答案设法将一个成员初始化为错误的值,并且(b)它使用了所有可能的非非自然方法中最少的清理来完成它。 – 2015-02-08 05:17:37
@ Cheersandhth.-Alf(a)我不够聪明,不知道会是什么成员。我诚实地尝试。 (b)我会说这是非常不干净的,也是* working *的最短路径。它不是*“最不干净”*,但我不会用例子来痛苦你,我敢肯定,你并没有对这种直觉感到失望。 – 2015-02-08 19:20:03