极客班干货第一周:
死磕自己,成长大家。
废话少说,直击重点,本周总结:
(1)构造函数尽量用initialization List;
(2)书写函数时,确定函数是否需要加const;
(3)参数传递尽量使用引用,能否用const要视情况而定;
(4)返回参数尽量用引用,若是函数内新建的局部变量必定不能用引用;
(5)Class declaration 中数据尽量放在private,函数大部分放在public中。可以使用友元函数,可以直接获取私有成员。
===================交流群经典语录=======================
1、最好的动态内存管理原则是谁new谁负责delete,而且尽量在一个函数内做。
2、在成熟的类库中,一个函数返回一些new的动态内存,然后让caller去负责delete,也是很常见的。(虽然原则还是尽量避免)
3、另外一种做法是在函数调用之前就把动态内存创建好。p=new... ; func(p); delete p;
4、在实际应用中,不建议容器做返回类型,用输出参数形式比较好,比如:std::vector<T>& output,建议尽量用stl而不是原生数组,即函数运用输入输出参数,双向操作。
5、编程最大的艺术就是反复,反复,再反复。
6、这要取决于:基础,学习的投入,职业目标。如果是定位BAT或者硅谷高端一些的岗位,还需要高级班的学习。如果是中档岗位,这个班级的课程,大家只要保证学习质量,技术方面基本都没问题(希望高级班能够优惠)。
7、 任何类型都可以做返回值。
8、但如果是size很大的容器对象,返回时做拷贝构造的成本可能会很高,可以采用右值引用,可以减少额外的拷贝构造函数和析构函数的开销。并且在函数里的局部变量可以通过右值引用的方式返回。
9、 inline的需求主要是看代码量是否足够小,从而免除函数调用的plumbing成本。与运算符,还是什么无直接关系。只不过很多运算符的函数体都很小,所以将它们inline很常见。不过提示一下inline只是programmer对compiler的建议,而采纳不采纳compiler会有自己的决定。
10、一定要在思考下去写代码,不仅know how, 也要know why, 是培养良好技术思维的前提。
=====================补充杂谈==========================
本周涉及到的一些补充杂谈,个人能力有限,可能有不足之处,共同学习,有心者可继续补充,总结如下:
1、C/C++中随机数生成:
因为rand()函数是按指定的顺序来产生整数,因此每次执行上面的语句都打印相同的两个值,所以说C语言的随机并不是真正意义上的随机。
为了程序在每次执行时都能生成一个新序列的随机值,我们通常通过为随机数生成器提供一粒新的随机种子。函数srand()(来自stdlib.h)可以为随机数生成器播散种子。只要种子不同rand()函数就会产生不同的随机数序列。srand()称为随机数生成器的初始化器。
调用方法是srand((unsigned)time(NULL));但是又不能在每次调用rand()的时候都用srand((unsigned)time(NULL));来初始化,因为现在计算机运行时间比较快,当连续调用rand()时,系统的时间还没有更新,所以得到的随机种子在一段时间内是完全相同的,因此一般只在进行一次大批随机数产生之前进行一次随机种子的初始化。 srand()函数定义: void srand (unsigned int seed); 通常可以利用geypid()或time(0)的返回值来当做seed 如果你用time(0)的话,要加入头文件#include<time.h>。
2、C++右值引用:
理解右值引用是学习“移动语义”的基础,必须先区分左值和右值。对于左值和右值的定义,大家都有一个常见的误解是:等号左边的就是左值,等号右边的就是右值。左值和右值都是针对表达式而言的,左值是指表达式结束后依然存在的持久对象,右值是指表达式结束后不再存在的临时对象。区分左值和右值的一个快捷方法是:看能不能对表达式取地址,如果能,则为左值;如果不能,则为右值。
详细介绍:右值引用可以减少额外的拷贝构造函数和析构函数的开销。
=====================作业总结==========================
回顾题目:
为Date类实现如下成员:
1. 构造器,可以初始化年、月、日。
2. 大于、小于、等于(> 、< 、==)操作符重载,进行日期比较。
3. print() 打印出类似 2015-10-1 这样的格式。
然后创建两个全局函数:
1. 第1个函数 CreatePoints生成10个随机的Date,并以数组形式返回;
2. 第2个函数 Sort 对第1个函数CreatePoints生成的结果,将其按照从小到大进行排序。
最后在main函数中调用CreatePoints,并调用print将结果打印出来。然后调用Sort函数对前面结果处理后,并再次调用print将结果打印出来。
程序编写:
//=========================data.h============================
#ifndef _DATA_
#define _DATA_
// forward declaration
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
#define DATA_SiZE 10
class Data;
//class declaration
class Data
{
public:
Data (int y = 0, int m = 0, int d = 0):ye(y),mon(m),da(d) {}
void print();
int year() const {return ye;}
int month() const {return mon;}
int day() const {return da;}
private:
int ye,mon,da;
friend bool operator > (const Data& data1, const Data& data2);
friend bool operator < (const Data& data1, const Data& data2);
friend bool operator == (const Data& data1, const Data& data2);
};
//class definition
inline void
Data::print()
{
cout<<ye<<'-'<<mon<<'-'<<da<<endl;
}
inline int
year(const Data& data)
{
return data.year();
}
inline int
month(const Data& data)
{
return data.month();
}
inline int
day(const Data& data)
{
return data.day();
}
inline bool
operator > (const Data& data1, const Data& data2)
{
return ( year(data1)>year(data2) || ( year(data1)==year(data2) && (month(data1)>month(data2)))
|| ( year(data1)==year(data2) && (month(data1)==month(data2)) && (day(data1)>day(data2))));
}
inline bool
operator < (const Data& data1, const Data& data2)
{
return ( year(data1)<year(data2) || ( year(data1)==year(data2) && (month(data1)<month(data2)) )
|| ( year(data1)==year(data2) && (month(data1)==month(data2)) && (day(data1)<day(data2)) ) );
}
inline bool
operator == (const Data& data1, const Data& data2)
{
return year(data1)==year(data2) && (month(data1)==month(data2)) && (day(data1)==day(data2));
}
inline int
random(const int start,const int end)
{
return start+(rand()%(end-start+1));
}
inline Data*
CreatePoints()
{
int i;
Data *data = new Data[DATA_SiZE];
//special month of days
int NumOfDays[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int randYear,randMonth;
cout<<"-------------------Before Sort------------------"<<endl;
srand((int)time(0));
// srand((unsigned)time(NULL));
for(i=0;i<DATA_SiZE;i++){
randYear = random(1900,2050);//year scope [1900,2050]
randMonth = random(1,12);
//isLeapYear
if(randYear%400 ==0 || (randYear%100 != 0 && randYear%4 ==0)){
NumOfDays[1] = 29;
}else{
NumOfDays[1] = 28;
}
data[i]=Data(randYear, randMonth,random(1,NumOfDays[randMonth-1]));
data[i].print();
}
return data;
}
inline void
Sort(Data* data)
{
int i,j;
Data tmp(0,0,0);
for(i=0;i<DATA_SiZE;i++){// from small to big,time cost is O(n^2)
for(j=i+1;j<DATA_SiZE;j++){
if(data[i]>data[j]){
tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
}
}
cout<<"-------------------After Sort------------------"<<endl;
for(i=0;i<DATA_SiZE;i++)
{
data[i].print();
}
}
//consider the smart pointer int the later,optimize the memory.
#endif // _DATA_
//=========================data.cpp===========================
#include "data.h"
int main()
{
Data* data_new = CreatePoints();
Sort(data_new);
delete[] data_new;
return 0;
}
题目总结:
1、调用CreatePoints()函数采用了new的方式,那就得delete,只是看你delete的方式。第一周作业我在Sort函数中delete了,其实功能与在主函数中delete是一样的。老师点评是在sort中是不太合理的。我想了想从工程原则,可能在主函数中delete相对合理,但是用户必须记得delete,这又是它的不太合理之处。所以编程过程中要考虑全面,做到尽量合理。
2、这里说明一下,重载运算符的时候我使用了友元函数,友元函数可以直接访问另一个类的私有成员,这是它的优点,但是不足之处就是破坏了类的封装性。
3、从现在开始,编程要基于工程原则出发,重点是满足工程需要,而不是简单实现功能。
著作权由godfrey所有,欢迎转载,也欢迎大家指出其中的不足,共同交流进步。