知乎:https://www.zhihu.com/people/monkey.d.luffy Android高级开发交流群2: 752871516
全部博文(315)
分类: C/C++
2012-02-27 23:15:22
/*file: leapYear.cpp
* 由leapyear来引申简单笔记,主要是类的相关!
*
*/
#include
#include
#include
#include
using namespace std;
class Date{
//以下变量默认私有
int year;
int month;
int day;
public:
Date(){
//year = 1998; //useless?
//month = 12;
//day = 12;
cout << "Construct....\n";
}
~Date(){
cout << "Destruct...\n";
}
Date(int y, int m, int d){ //构造函数重载
year = y;
month = m;
day = d;
}
//===============================================================
void set(int y, int m, int d);
/*
引用规避了指针的风险,对引用不管怎么赋值都是安全的
int &b = a;
int *p = a;
在程序的应用中,可能会不小心就使用p = 1;而不是*p = 1;这样的赋值语句,而前者直接改地址值的行为是很危险的,因为0x1这个地址可能存放的是重要数据,禁止读写的区域。而引用就不会有这个问题
*/
//void set(string s);
void set(string &s); //重载,同时传递字符串的引用;
bool isLeapYear() const; //常成员函数不允许改变对象的值;
void printDate() const;
//===============================================================
//申明为friend表明这是“友元”,既然是友元,就可以访问类的私有成员变量了。
//Date operator+(const Date& a, const Date& b);
friend Date operator+(const Date& a, const Date& b);
friend Date add(const Date& a, const Date& b);
};
void Date::set(int y, int m, int d)
{
year = y;
month = m;
day = d;
}
void Date::set(string &s)
{
year = atoi(s.substr(0, 4).c_str());
month = atoi(s.substr(5, 2).c_str());
day = atoi(s.substr(8, 2).c_str());
}
bool Date::isLeapYear() const
{
return (year%4 == 0 && year%100 != 0) || (year%400 == 0);
}
inline void Date::printDate() const
{
cout << setfill('0');
cout << setw(4) << year << '-' << setw(2) << month << '-' << setw(2) << day << " ---";
cout << setfill(' ');
}
Date operator+(const Date& a, const Date& b)
{
Date s;
s.set((a.year + b.year), (a.month + b.month), (a.day + b.day));
return s;
}
Date add(const Date& a, const Date& b)
{
Date s;
s.set((a.year + b.year), (a.month + b.month), (a.day + b.day));
return s;
}
int main(int argc, const char *argv[])
{
//===============================================================
//Date *dt = new Date; //can work
Date *dt = new Date(2000, 12, 6); //can work
//这里创建了一个类对象实例,所以显示调用了构造函数;在整个程序结束之后,这个对象才会被销毁;所以我的测试结果中最后还有一个析构函数被调用;
//所以两种方式创建对象的形式不同,其原理也不同!
Date dtt(2000, 12, 6);
//dt->set(2000, 12, 6);
//dt->set("2000-12-06"); //如果原来的参数是一个引用;那么这样会出错的;应该是:string ss = "2000-12-06"; string sq = &ss;
string ss = "2000-12-06";
string &sq = ss;
//dt->set(ss); //can work
dt->set(sq);
if(dt->isLeapYear()){
dt->printDate();
cout << "leape year!\n";
}
free(dt);
//===============================================================
#if 1
Date *aa = new Date(2000, 12, 6); //can work
Date *bb = new Date(2000, 12, 6); //can work
//const Date &a = *aa; //传递引用
//const Date &b = *bb;
//operator+(a, b).printDate();
//(a + b).printDate(); //这种方式默认会调用add函数;
//add(a, b).printDate();
//构造函数在打印之前调用,在我们传入*aa之后才创建的对象;
//在传入对象之前没有调用构造函数,之后立即调用析构函数;
operator+(*aa, *bb).printDate();
(*aa + *bb).printDate(); //这种方式默认会调用add函数;
add(*aa, *bb).printDate();
free(aa);
free(bb);
Date nopa; //调用无参构造函数;如果无无参构造函数,而定义了有参构造函数,此用法会报错的!
nopa.set(2006, 12, 23);
nopa.printDate();
#endif
return 0;
}
//===================结果测试===================================
/*
2000-12-06 ---leape year!
Construct....
4000-24-12 ---Destruct...
Construct....
4000-24-12 ---Destruct...
Construct....
4000-24-12 ---Destruct...
Destruct...
*/
//===================经验之谈(C++程序设计)====================
//设计函数的时候,参数若为类类型,则一般都用引用类型;若为内部数据类型,则不用引用类型,这是重要的经验之谈;
//我们在设计operator+操作符函数的时候,在内部定义了局部的类对象,这是不太好的习惯,会无端造成内存空间泄露;
//还有一个问题是关于流的问题:<<返回的流的引用,而不是对象的引用了,这是因为返回流的引用对于<<来说符合要求,而如果<<操作的是非引用型的流,那么将产生一种基于设备的流的复制,这样也就是临时有了一个符合的操作,显然这种复制品慢了很多,性能自然就下降了!
//后面还有一个增量符的问题:我估计用的地方不会太多,不过要知道增量符分为前增量符和后增量符的差别;其实看看就明白,在c中我们知道定义一个整型变量a,赋值后,让其自增++,然后是不能作为左值的,其实这个后增量符也是如此,一旦自增过,整体在自增就会报错了。其它好像也没啥很重要的;这些都是细节!
//这是关于成员操作符的问题:前面说过成员函数,现在说成员操作符了,你就知道其实它就是在类内部实现函数的定义;以前还不太懂,现在好理解多了;和一般操作符区别就是,它省略了+之前的那个对象的参数,因为在内部嘛,所以我们就省略了第一个参数,之间使用类的成员变量来作为第一个参数;就是这样:
//class Date{
// int year;
// Date operator+(const Date& b){
// Date d;
// d.set(year + b.year);
// return d;
// }
//};
//静态成员{静态数据成员和静态成员函数,静态数据成员和在C语言,功能类似,下一次是上次的保存值+相关操作后的结果;在类中的解释就是:
//只维持在一个对象中的一份拷贝;
//对于静态成员函数来说就是:可以独立于类而存在,意思就是我们可以通过 类名::静态成员函数名 的方式来调用它,我相信还是能理解的,在c中我们说静态的数据存放在数据区,而局部的不是静态的变量则在栈中,一旦函数生命周期到了,那么局部的数据说不定咋变,所以我们能够访问数据区的数据,这是在编译完后就存放好的,而不是要运行时才产生的。
//当然还要注意写法,如果在类内部申明需要加static,然后在外部去定义的话那么static就不要去加了,这点注意就好了!
//至于“友元”,前面见识过了,后面还说了整个类可以是友元,该友元又称为友类;同时一个类的成员函数可以是另一个类的友元,即使把教师的职责的成员函数放到学生的类中,作为学生类的友元函数,这样可以访问学生的一切私有的数据了!