从另一个构造函数调用默认构造函数
Calling the default constructor from another constructor
我试图让重载构造函数调用默认构造函数,但它只给我垃圾编号。我想让它做的是识别输入的日期是否无效,因此将其默认为 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
,从而删除关于构造函数参数无效这一事实的所有信息……
不过,none个选项都不错!就意图而言,将参数错误视为对默认值的请求本身是非常不好的。相反,当您检测到参数错误时,抛出异常或终止,以便客户端代码手头不会有可能意外的对象。
例如,做
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" );
}
}
我试图让重载构造函数调用默认构造函数,但它只给我垃圾编号。我想让它做的是识别输入的日期是否无效,因此将其默认为 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
,从而删除关于构造函数参数无效这一事实的所有信息……
不过,none个选项都不错!就意图而言,将参数错误视为对默认值的请求本身是非常不好的。相反,当您检测到参数错误时,抛出异常或终止,以便客户端代码手头不会有可能意外的对象。
例如,做
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" );
}
}