C++类和对象 下
紧接上回,这次我们把Date类完善一下
运算符重载之++/--
前置++/--
计算当前日期的后一天/前一天
#pragma once
#include<iostream>
using namespace std;
class Date
{
public:
Date(int y = 2025, int m = 9, int d = 11)
{
_year = y, _month = m, _day = d;
}
void Print()
{
printf("%d-%02d-%02d\n", _year, _month, _day);
}
// 下面我们来实现这两个函数。注意这是前置++与前置--
Date& operator++ ();
Date& operator-- ();
private:
// ++和--会频繁求当前月的天数
int get_day_of_month(int year, int m)
{
static int d[13] = {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(m != 2) return d[m];
if(_year % 4 == 0 && _year % 100 != 0 || _year % 400 == 0)
return d[2] + 1;
else return d[2];
}
int _year;
int _month;
int _day;
};
代码实现:
Date& Date::operator++ ()
{
_day++;
if(_day > get_day_of_month(_year, _month))
{
_day = 1;
_month++;
if(_month == 13)
{
_month = 1;
_year++;
}
}
return *this;
}
Date& Date::operator-- ()
{
_day--;
if(_day == 0)
{
_month--;
if(_month == 0)
{
_month = 12;
_year--;
}
_day = get_day_of_month(_year, _month);
}
return *this;
}
测试一下:
int main()
{
Date d1(2025, 2, 10);
Date d2(2025, 3, 1);
while(d1 != d2)
{
d1.Print();
++d1;
}
return 0;
}
后置++/--
为了跟前置++/--区分开,C++规定后置++/--参数要多一个int
Date operator++ (int);
Date operator-- (int);
代码实现:
// 注意后置++/--的返回值
Date Date::operator++ (int)
{
Date t = *this;
_day++;
if(_day > get_day_of_month(_year, _month))
{
_day = 1;
_month++;
if(_month == 13)
{
_month = 1;
_year++;
}
}
return t;
}
Date Date::operator-- (int)
{
Date t = *this;
_day--;
if(_day == 0)
{
_month--;
if(_month == 0)
{
_month = 12;
_year--;
}
_day = get_day_of_month(_year, _month);
}
return t;
}
测试:
int main()
{
Date d(2025, 9, 12);
Date d1 = d++;
d.Print();
d1.Print();
return 0;
}
运行结果

运算符重载之+=/-=
有了前两个代码我们就可以求距离该日期n天后(或n天前)的日期
Date& operator+= (int n);
Date& operator-= (int n);
代码实现:
Date& Date::operator+= (int n)
{
while(n--) (*this) ++;
return *this;
}
Date& Date::operator-= (int n)
{
while(n--) (*this) --;
return *this;
}
测试,结果可以对比 在线日期计算器
int main()
{
Date d1(2025, 9, 12);
d1 += 333330;
d1.Print();
return 0;
}
运算符重载之+/-
日期 + 天数n: n天后的日期
日期 + 日期:无意义
日期 - 天数n: n天前的日期
日期 - 日期:两个日期间的天数
需要实现的相关函数如下:
Date operator+(int n);
Date operator-(int n);
int operator- (const Date& d);
代码实现
Date Date::operator+ (int n)
{
Date t = *this;
t += n;
return t;
}
Date Date::operator-(int n)
{
Date t = *this;
t -= n;
return t;
}
int Date::operator- (const Date& d)
{
// 大 - 小:天数为正;反之为负
int flag = 1;
Date begin = d;
Date end = *this;
if(*this < d)
{
flag = -1;
begin = *this, end = d;
}
int cnt = 0;
while(begin != end)
{
cnt++;
begin++;
}
return cnt * flag;
}
测试:
int main()
{
Date d1(1999, 1, 1);
Date d2(2025, 9, 12);
cout << (d1 - d2) << endl;
cout << (d2 - d1) << endl;
Date d3(2125, 9, 12);
cout << (d3 - d2) <<endl; // 人生不过三万天 ~
return 0;
}
运算符重载之<< / >>
int main()
{
Date d(2025, 2, 28);
d.Print(); // 每次打印都要调用Print,能否像下面那样打印日期呢?
// cout << d;
return 0;
}
我们先来理一下为什么cout可以自动识别类型
cout其实是ostream类的一个对象,库里面已经写好了相关的运算符重载

转念一想在类里面写出了下面的代码
// 补充:cout只能传引用,ostream的拷贝构造被禁用了。也不要加const
void operator<< (ostream& out)
{
out << _year << '-' << _month << '-' << _day;
}
转到main函数测试
int main()
{
Date d(2025, 2, 28);
cout << d;
return 0;
}
运行一下,呕吼,编译报错。
为什么呢?
如果显示调用的话,应该这样写:d.operator<<(cout); 由于运算符重载中,参数顺序和操作数顺序是一致的,而我把顺序搞反了。正确写法如下:
int main()
{
Date d(2025, 2, 28);
d << cout; // d.operator<< (cout);
return 0;
}
改完后成功运行,但是不太符合习惯。如何让ostream做第一个参数,Date做第二个参数呢?我们要在类外面写运算符重载
// 保持参数类型的顺序为ostream,Date
ostream& operator<< (ostream& out, Date& d)
{
out << d._year << '-' << d._month << '-' << d._day;
return out;
}
// 细心的同志可能发现我把返回值改为了ostream&,这是为了支持连续输出,类似上篇内容的赋值重载
但是又存在一个问题,Date类里的成员变量访问权限都是private,类外面根本就无法访问!如何解决?
- 像Java那样提供
get与set函数 - 用友元,在
Date类里面加入下面代码(放在public或者private区域都行)
friend ostream& operator<< (ostream& out, Date& d);
friend修饰的函数可以访问类里面private的成员变量或成员函数。(friend修饰的函数放在类里面不存在隐含的this)
同理也可以写出流提取重载:
类外面:
istream& operator>> (istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
注意还要在类里面加上声明:
friend istream& operator>> (istream& in, Date& d);
const成员
先看下面的代码:
class Date
{
public:
// ... 省略别的代码
void Print()
{
printf("%d-%02d-%02d\n", _year, _month, _day);
}
// ...省略成员变量
}
int main()
{
const Date d(2025, 2, 28); //对象被const修饰
d.Print();
return 0;
}
会编译报错,原因是权限放大
this指针的类型是Date* const,而d调用Print()时会把d的地址传给this,即Date* const this = &d,然而&d的类型是const Date*
补充const修饰指针的一些知识:
const在*之前,表示不可修改指向的内容,但可以修改指向const在*之后,表示不可修改指向,但可以修改指向的内容
这时候我们其实要修改this的类型。C++规定了如下写法:
class Date
{
public:
// ... 省略别的代码
// 在函数后面加上const
// 这样this的类型就由原来的Date* const 变成了 const Date* const,就不涉及权限放大了
void Print() const
{
printf("%d-%02d-%02d\n", _year, _month, _day);
}
// ...省略成员变量
}
int main()
{
const Date d(2025, 2, 28);
d.Print(); //const成员可以调用
Date d1(2027, 9, 12);
d1.Print(); //非const成员也可以调用。权限可以缩小
return 0;
}
至此,Date类大致搞定了,但是还存在一些潜在的bug
例如本篇开头的构造函数:
Date(int y = 2025, int m = 9, int d = 11)
{
_year = y, _month = m, _day = d;
}
万一有人写了这样的代码:
Date d(2000, 999, 999);
程序就会出一系列的bug 。一行代码写业务,百行代码防刁民。 为此我们添加额外判断:
Date(int y = 2025, int m = 9, int d = 11)
{
if(y <= 0 || m <= 0 || m > 12 || d <= 0 || d > get_day_of_month(y, m))
{
puts("日期非法");
exit(-1);
}
_year = y, _month = m, _day = d;
}
与此相关的还有operator+= / -=
Date& Date::operator+= (int n)
{
while(n--)
(*this) ++;
return *this;
}
Date& Date::operator-= (int n)
{
while(n--)
(*this) --;
return *this;
}
如果有人写成如下代码,就会死循环
Date d;
d -= -1000;
改完后的代码
Date& Date::operator+= (int n)
{
if(n >= 0)
{
while(n--)
(*this) ++;
}
else
(*this) -= -n;
return *this;
}
Date& Date::operator-= (int n)
{
if(n >= 0)
{
while(n--)
(*this) --;
}
else
(*this) += -n;
return *this;
}
文章最后贴上完整日期类代码以及相关练习题
日期类代码
日期类练习题
再谈构造函数
先看段代码:
#include<iostream>
using namespace std;
// A类无法修改内部成员
class A
{
public:
A(int x)
{
_a = x;
}
private:
int _a;
};
class B
{
public:
private:
A _aa;
int _b;
};
int main()
{
B b;
return 0;
}
代码编译错误。编译器会生成B的构造函数,会调用A的默认构造初始化_aa,但A不提供默认构造,这就很难受。想着给B写一个构造:
class B
{
public:
B()
{
// _aa.A(1); // 不可显式调用构造,但是不写这一行也会编译报错
_b = 0;
}
private:
A _aa;
int _b;
};
为了解决上面那种情况,就要用初始化列表了
初始化列表
用法如下:
class A
{
public:
A(int x)
{
_a = x;
}
private:
int _a;
};
class B
{
public:
B()
:_aa(1) // 调用A(int x)初始化_aa
, _b(5) // 用5初始化_b
{}
private:
A _aa;
int _b;
};
初始化列表在函数声明跟函数体之间,以冒号开始,用逗号分割,每个成员变量用其后面括号内的值初始化
一些相关性质:
① 初始化列表本质上可以理解为每个对象中的成员定义的地方
② 必须在初始化列表进行初始化的类型:1.const类型,2.引用类型,3.没有默认构造的自定义类型
class T
{
int _t;
public:
T(int x)
{
_t = x;
}
};
class A
{
const int _a;
int& _ref;
T _tt;
public:
A(int& rr)
:_a(1) //这三者必须在初始化列表初始化
,_ref(rr)
,_tt(2)
{
_ref = rr; // 函数体内并非初始化,而是赋值
}
};
③ 初始化列表不管你写不写,每个成员变量都会按在类里面声明的顺序依次走一遍。 自定义类型调用其默认构造;内置类型不做处理(如果给了缺省值,初始化列表就会用缺省值初始化。缺省值其实是给初始化列表用的)
小练习:
class A
{
int _a2;
int _a1;
public:
A(int a)
:_a1(a)
,_a2(_a1)
{}
void Print()
{
cout << _a1 << ' ' << _a2 << endl;
}
};
int main()
{
int n;
A a(1);
a.Print();
return 0;
}
上述的代码会输出 1 1 吗?
虽然初始化列表的顺序是_a1, _a2,但成员变量在类里面声明的顺序为_a2, _a1。代码会按照声明的顺序先初始化_a2,再初始化_a1。所以输出结果是:1 随机值
隐式类型转换
内置类型的隐式类型转换
int main()
{
int a = 3.3; // a是int,3.3是double。编译器会先把3.3转换成int放在临时变量中,然后再拷贝给a
/*代码等价于:
const int tmp = 3.3;
int a = tmp;
*/
// int& a1 = 3.3; // 临时变量具有常性,会权限放大
const int& a1 = 3.3;
return 0;
}
单参数隐式类型转换
#include<iostream>
using namespace std;
class A
{
int _a;
public:
A(int x)
:_a(x)
{
cout << "A(int x)" << endl;
}
A (const A& a)
:_a(a._a)
{
cout << "A (const A& a)" << endl;
}
};
int main()
{
A a1(1); // 构造
A a2 = a1; // 拷贝构造
A a3 = 1; // 这里是隐式类型转换。内置类型转自定义类型
//原理:编译器会调用A的单参数构造,用1构造出临时对象,然后在拷贝给a3。等价于下面的代码
/*
const A tmp(1);
A a3 = tmp;
*/
return 0;
}
Dev-C++运行结果如下:

但是你们的编译器可能只会输出A(int x),原因是编译器进行了拷贝省略优化(连续的构造+拷贝构造 -> 优化为直接构造)。
这里建议用老版编译器观察,并加入命令-fno-elide-constructors以关闭优化。
Dev-C++中,工具 -> 编译选项

了解了底层原理之后,再看一段代码
class A
{
int _a;
public:
A(int x)
:_a(x)
{
cout << "A(int x)" << endl;
}
A (const A& a)
:_a(a._a)
{
cout << "A (const A& a)" << endl;
}
};
int main()
{
// int& x = 3.3; // 编译错误
const int& x = 3.3; // 3.3转换成int会产生临时变量,临时变量具有常性
////与上面类似:
// A& a = 1; // 编译错误
const A& a = 1; // 1转换成对象会产生临时对象,临时对象具有常性
return 0;
}
多参数隐式类型转换
class A
{
int _a;
int _a1;
int _a2;
public:
A(int x)
:_a(x)
{
cout << "A(int x)" << endl;
}
A(int a1, int a2)
:_a(0)
,_a1(a1)
,_a2(a2)
{
cout << "A(int a1, int a2)" << endl;
}
A (const A& a)
:_a(a._a)
{
cout << "A (const A& a)" << endl;
}
};
int main()
{
A a(1); // 调用单参数构造
A a1 = 1; // 隐式类型转换
A aa(1, 2); // 调用多参数构造
A aa1 = {1, 2}; // 隐式类型转换,这个C++11以后支持
// A a = (1, 2); 后面的会识别成逗号表达式,等价于 A a = 2;
return 0;
}
explicit关键字
若想关闭隐式类型转换,就在函数前面加上explicit
class A
{
int _a;
int _a1;
int _a2;
public:
// 禁止隐式类型转换
explicit A(int x)
:_a(x)
{
cout << "A(int x)" << endl;
}
// 禁止隐式类型转换
explicit A(int a1, int a2)
:_a(0)
,_a1(a1)
,_a2(a2)
{
cout << "A(int a1, int a2)" << endl;
}
};
int main()
{
A a1 = 1; // err
A aa1 = {1, 2}; // err
return 0;
}
static 成员
静态成员为所有类、类的对象所共享,不属于某个具体的对象,存放在静态区
静态成员变量
class A
{
int _a1;
int _a2;
static int _s; // 被static修饰的成员变量就是静态成员变量
};
int main()
{
cout << sizeof(A) << endl; // 8
A a1;
cout << sizeof(a1) << endl; // 8
// 静态成员变量不在对象中,在静态区
return 0;
}
静态成员变量需要在类外初始化
class A
{
int _a1 = 1;
int _a2 = 2;
public:
static int _s; // 静态成员变量声明
};
// 静态成员的定义
int A::_s = 1;
int main()
{
A a;
cout << a._s << endl; // 用类的对象访问
cout << A::_s << endl; // 用类访问
// 静态成员变量一般设为公有
return 0;
}
但如果将A类的_s访问权限改为私有:
class A
{
int _a1 = 1;
int _a2 = 2;
static int _s; // 静态成员变量声明
};
// 静态成员的定义
int A::_s = 1; // 这里仍然可以定义
int main()
{
A a;
// cout << a._s << endl; // err
// cout << A::_s << endl; // err
return 0;
}
虽然_s是私有,但静态成员的定义不受访问控制限制(访问静态成员还是受限制的)
注意:静态成员变量不可用缺省值初始化
class A
{
int _a1 = 1;
int _a2 = 2;
static int _s = 3; // err
// 缺省值本质是给初始化列表使用的,_s不会走初始化列表
};
静态成员函数
访问经验成员变量还可以提供静态成员函数
class A
{
int _a1 = 1;
int _a2 = 2;
static int _s; // 静态成员变量声明
public:
static int Get_s()
{
return _s;
}
// 不过感觉有点脱裤子放屁——多此一举。还不如直接把_s设为public呢
};
// 静态成员变量的定义
int A::_s = 0;
int main()
{
A a;
cout << A::Get_s() << endl;
cout << a.Get_s() << endl;
return 0;
}
注意静态成员函数没有隐含的this,无法访问非静态成员变量。
class A
{
int _a1 = 1;
int _a2 = 2;
static int _s; // 静态成员变量声明
public:
static int Get_s()
{
cout << _a1 << ' ' << _a2 << endl; // err 编译报错
return _s;
}
};
// 静态成员变量的定义
int A::_s = 0;
int main()
{
return 0;
}
友元
友元函数
上文运算符重载<< / >>已经略微介绍了,再回顾一下
class Date
{
public:
Date(int y = 2025, int m = 9, int d = 11)
{ _year = y, _month = m, _day = d; }
void Print() const
{ printf("%d-%02d-%02d\n", _year, _month, _day); }
private:
// Date类把此函数当作朋友。也可以说此函数是Date类的朋友
friend ostream& operator<< (ostream& out, Date& d);
int _year;
int _month;
int _day;
};
// Date类把此函数当作朋友,此函数就可以访问Date类型的对象的私有成员
ostream& operator<< (ostream& out, Date& d)
{
// _year, _month, _day都是私有,但此函数是Date类的friend,可以访问Date的私有成员
out << d._year << '-' << d._month << '-' << d._day;
return out;
}
友元函数是定义在类外面的普通函数,在类内部加friend声明
友元类
class A
{
int _a = 1000;
public:
void Print() { cout << _a << endl; }
friend class B; // A 把 B 当朋友
};
class B
{
int _b;
public:
void func(A _A)
{
cout << _A._a << endl; // A类里的_a是私有
// A 把 B 当朋友,B里面的成员函数都可以是A类的友元函数,都可以访问A类型对象的私有成员
}
};
int main()
{
A a;
B b;
b.func(a);
return 0;
}
注意:
① 友元关系是单向的
class A
{
int _a;
public:
void Print() { cout << _a << endl; }
void funcA(B b)
{
// B类 没有说明与 A类的关系,换句话说 B没把A当朋友
cout << b._b << endl; // 所以A类中无法访问B类对象的私有成员,编译报错
}
friend class B; // A把 B当朋友
};
class B
{
int _b;
A _A;
public:
void func()
{
_A._a = 1; // B 是 A 的朋友,B里面的成员函数都可以是A类的友元函数,都可以访问A类的私有成员
}
};
int main()
{
return 0;
}
② 友元关系不可传递
A把B当朋友,B把C当朋友,不能推出A把C当朋友
class A
{
int _a = 10;
friend class B; // A把 B当朋友
};
class B
{
int _b = 11;
friend class C; // B把 C当朋友
};
class C
{
int _c = 12;
public:
void func(B b, A a)
{
cout << b._b << endl;
// cout << a._a << endl; // err 无法访问
}
};
int main()
{
A a;
B b;
C c;
c.func(b, a);
return 0;
}
③友元这种关系尽量少用,一定程度上破坏了封装
内部类
如果一个类定义在另一个类的内部,这个内部的类就叫做内部类。内部类是一个独立的类,仅受外部类的类域限制。内部类天生是外部类的友元。
class A
{
int _a;
public:
class B // B天生就是A的友元。相当于在A里面加上friend class B
{
int _b;
public:
B(int x = 1)
:_b(x)
{}
};
};
int main()
{
cout << sizeof(A) << endl;
A a;
A::B b; // 用B类创建对象
return 0;
}
匿名对象
class A
{
int _a;
public:
A(int x = 1)
:_a(x)
{ cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
};
int main()
{
A a1(1); // 对象名字是a1
A a2(2); // 对象名字是a2
A(3); // 没有名字,称为匿名对象。其生命周期只在当前这一行
A a3;
return 0;
}
运行结果

class A
{
int _a;
public:
A(int x = 1)
:_a(x)
{ cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void Print() { cout << _a << endl; }
};
// 匿名对象的特殊之处
int main()
{
// A& a = A(3); // 引用匿名对象需要加const,具体原理在C++11的右值中讲
const A& a = A(3); // 会把匿名对象的生命周期变成a的生命周期
A(3).Print(); // 虽然引用需要加const,但匿名对象可以调用非const成员函数
return 0;
}
运行结果

对比不加引用的结果
// ... 其他代码同上
int main()
{
A(3); // 不加引用,声明周期只在当前这一行
A(3).Print();
return 0;
}

再看个代码回顾一下之前的内容
class A
{
int _a;
public:
A(int x = 1)
:_a(x)
{
cout << "A()" << endl;
}
A(const A& a)
{
cout << "A(const A& a)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
void Print()
{
cout << _a << endl;
}
};
void func(const A& a)
{
;
}
int main()
{
A a;
func(a); // 普通对象传参
func(A(2)); // 匿名对象传参
func(2); // 隐式类型转换
return 0;
}
至此,类和对象已经入门
Date类完整代码
Date.h:
#pragma once
#include<iostream>
using namespace std;
class Date
{
public:
Date(int y = 2025, int m = 9, int d = 11)
{
if(y <= 0 || m <= 0 || m > 12 || d <= 0 || d > get_day_of_month(y, m))
{
puts("日期非法");
exit(-1);
}
_year = y, _month = m, _day = d;
}
void Print() const
{ printf("%d-%02d-%02d\n", _year, _month, _day); }
bool operator< (const Date& d) const;
bool operator> (const Date& d) const;
bool operator== (const Date& d) const;
bool operator<= (const Date& d) const;
bool operator>= (const Date& d) const;
bool operator!= (const Date& d) const;
Date& operator++ ();
Date& operator-- ();
Date operator++ (int);
Date operator-- (int);
Date& operator+= (int n);
Date& operator-= (int n);
Date operator+(int n) const;
Date operator-(int n) const;
int operator- (const Date& d) const;
private:
//friend 修饰的函数没有隐含的this
friend ostream& operator<< (ostream& out, Date& d);
friend istream& operator>> (istream& in, Date& d);
int get_day_of_month(int year, int m)
{
static int d[13] = {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(m != 2) return d[m];
// 特判闰年
if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
return d[2] + 1;
else return d[2];
}
int _year;
int _month;
int _day;
};
Date.cpp
#include"Date.h"
bool Date::operator< (const Date& d) const
{
if(_year != d._year) return _year < d._year;
if(_month != d._month) return _month < d._month;
return _day < d._day;
}
bool Date::operator== (const Date& d) const
{
return _day == d._day && _month == d._month && _year == d._year;
}
bool Date::operator<= (const Date& d) const
{
return *this < d || *this == d;
}
bool Date::operator> (const Date& d) const
{
return !(*this <= d); // 不<=就是大于
}
bool Date::operator>= (const Date& d) const
{
return !(*this < d);
}
bool Date::operator!= (const Date& d) const
{
return !(*this == d);
}
Date& Date::operator++ ()
{
_day++;
if(_day > get_day_of_month(_year, _month))
{
_day = 1;
_month++;
if(_month == 13)
{
_month = 1;
_year++;
}
}
return *this;
}
Date& Date::operator-- ()
{
_day--;
if(_day == 0)
{
_month--;
if(_month == 0)
{
_month = 12;
_year--;
}
_day = get_day_of_month(_year, _month);
}
return *this;
}
Date Date::operator++ (int)
{
Date t = *this;
_day++;
if(_day > get_day_of_month(_year, _month))
{
_day = 1;
_month++;
if(_month == 13)
{
_month = 1;
_year++;
}
}
return t;
}
Date Date::operator-- (int)
{
Date t = *this;
_day--;
if(_day == 0)
{
_month--;
if(_month == 0)
{
_month = 12;
_year--;
}
_day = get_day_of_month(_year, _month);
}
return t;
}
Date& Date::operator+= (int n)
{
if(n >= 0)
{
while(n--)
(*this) ++;
}
else
(*this) -= -n;
return *this;
}
Date& Date::operator-= (int n)
{
if(n >= 0)
{
while(n--)
(*this) --;
}
else
(*this) += -n;
return *this;
}
Date Date::operator+ (int n) const
{
Date t = *this;
t += n;
return t;
}
Date Date::operator-(int n) const
{
Date t = *this;
t -= n;
return t;
}
int Date::operator- (const Date& d) const
{
// 大 - 小:天数为正;反之为负
int flag = 1;
Date begin = d;
Date end = *this;
if(*this < d)
{
flag = -1;
begin = *this, end = d;
}
int cnt = 0;
while(begin != end)
{
cnt++;
begin++;
}
return cnt * flag;
}
ostream& operator<< (ostream& out, Date& d)
{
out << d._year << '-' << d._month << '-' << d._day;
return out;
}
istream& operator>> (istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
// 额外检查日期是否合法
if (d._year <= 0 || d._month <= 0 || d._month > 12 ||
d._day <= 0 || d._day > d.get_day_of_month(d._year, d._month))
{
puts("输入日期非法");
exit(-1);
}
return in;
}
Date类练习题
更多推荐
所有评论(0)