C语言中,可能中途return也可能最后return,destroy的地方很多,比较麻烦。
以下为C++进行的改进,俗称”天选之子“。
C++类型分为:内置类型(int,char,任意类型的指针)不处理,
自定义类型(class,struct,union联合体)调用他的构造
默认生成的构造函数对于内置类型的成员不做处理,对于自定义类型的成员,会去调用它的构造(不用传参的构造)
与析构函数相似
class Date
{
public:
Date()
{
_year = 1;
_month= 1;
_day= 1;
}
Date(int year, int month, int day)//带参的初始化
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
private:
//基本类型或内置类型,因为带int
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(2023, 9, 13);
d1.Print();
d2.Print();
return 0;
}
合并两个构造函数,用全缺省更好用
Date(int year=1, int month=1, int day=1)//全缺省
{
_year = year;
_month = month;
_day = day;
}
两个栈实现一个队列(push,pop,peek,empty)问题。
C
typedef struct {
ST pushst;
ST popst;
}MyQueue;
bool myQueueEmpty(MyQueue* obj);
MyQueue* myQueueCreate()
{
MyQueue* pq = (MyQueue*)malloc(sizeof(MyQueue));
StackInit(&pq->pushst);
StackInit(&pq->popst);
return pq;
}
void myQueueFree(MyQueue* obj)
{
assert(obj);
StackDestroy(&obj->pushst);
StackDestroy(&obj->popst);
return pq;
}
C++
class MyQueue {
public:
//默认生成的构造函数,对自定义类型,会调用他的默认构造函数。
void push(int x)
{}
//...
Stack _pushST;
Stack _popST;
};
int main()
{
MyQueue q;
return 0;
}
实际上是在初始化对象,特殊的成员函数。作用和Init相同。,主要任务不是开空间创造对象,而是初始化对象。
#include
using namespace std;
class Stack
{
public:
//成员函数
void Init(int n=4)
{
_a = (int*)malloc(sizeof(int) * n);
if (nullptr == a)
{
perror("malloc申请空间失败");
return;
}
capacity = n;
size = 0;
}
void Push(int x)
{
//...
a[size++] = x;
}
void Destroy()
{
//...防止内存泄漏,可以把这件事交给编译器,让他自动搞起来。
}
//...
private:
//成员变量
int* _a;
int _size;
int _capacity;
};
int main()
{
//定义一个栈
Stack st;
//初始化
st.Init(4);
st.Push(1);
st.Push(1);
st.Push(1);
st.Push(1);
//进行销毁
st.Destroy();
return 0;
}
class Stack
{
public:
Stack()
{
_a = nullptr;
_size = _capacity = 0;
}
Stack(int n)//有了构造函数的类就不需要Init的类
//构成函数重载
{
_a = (int*)malloc(sizeof(int) * n);
if (nullptr == _a)
{
perror("malloc申请空间失败");
return;
}
_capacity = n;
_size = 0;
}
void Push(int x)
{
//...
_a[_size++] = x;
}
void Destroy()
{
//...防止内存泄漏,可以把这件事交给编译器,让他自动搞起来。
}
private:
//成员变量
int* _a;
int _size;
int _capacity;
};
int main()
{//构造函数的调用
//定义一个栈
//Stack st;//无参,不带(),否则会报错
//因为是声明函数还是调用对象分不清楚。有点混淆
Stack st(4);//带参
//Stack st(4,3);
st.Push(1);
st.Push(1);
st.Push(1);
st.Push(1);
//进行销毁
st.Destroy();
return 0;
}
Stack st(4)不等同于st.Stack(4)
构造函数不能用对象调用,st定义好了才向下走。
destroy,和刚才构造函数的方法类似,定义一个函数让他自动调用。功能和构造函数相反,析构函数不是完成对象本身的销毁,析构函数进行清理资源,在对象出了作用域,生命周期销毁后进行调用。
~Stack()
{
free(_a);
_a=nullptr;
_size=_capacity=0;
}//只定义一个对象就释放一次,两个对象释放2次
Date(Date d)
{
_year = d._year;
_month = d._month;
_day = d._day;//拷贝构造
}//编译器不允许发生这种拷贝构造,会产生无穷递归,规定这个地方必须用引用
//普通整型,内置类型可以直接传递,但是自定义类型不可以。
//传值传参
void Func1(Date d)
{}//Func传参的时候是一个拷贝,把d1拷贝给d
//传引用传参
void Func2(Date& d)
{
}//d是d1的别名
int main()
{
Func1(d1);
return 0;
}
自定义类型不能编译器随便拷贝。内置类型编译器可以直接拷贝,自定义类型的拷贝需要调用拷贝构造。
按字节拷贝:浅拷贝
对于栈来说,浅拷贝两个栈指定同一空间,会析构两次。
C++规定自定义类型要调用一个拷贝构造,栈这样的类要调用一个深拷贝(自己去开一块空间)的拷贝构造。
要调用func1先传参,传参就是一个拷贝构造。
Date d2(d1);//对象实例化调用,先调用对应的构造函数,此时是拷贝构造Date (Date d);,调用拷贝构造之前要先传参d1传给d,传值传参又形成一个拷贝构造;拷贝构造要先传参,传值传参又是一个拷贝构造。。。。。递归下去。套娃
解决方法:引用。Date (Date &d);//d是d1的别名
拷贝构造也可以这么写:Date d2=d1;
拷贝构造一般加const。
Date (const Date &d);//权限缩小,权限可以缩小不可放大。
引用不需要调用函数。调用就是传参
指针也是内置类型。自定义类型必须用拷贝构造完成,编译器驾驭不了。
Date(const Date* d)
{
cout<<"Date(Date& d)"<<endl;
_year = d->_year;
_month = d->_month;
_day = d->_day;//不是拷贝构造
}//只是一个普通的构造函数
Date d4(&d1);
Dare d5=&d1;//复杂别扭
实现一个函数,实现多少天以后的日期。
int GetMonthDay(int year, int month)
{//if,else/switch,case
//数组
assert(month > 0 && month < 13);
int monthArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 2 && ((year % 4 == 0 && year % 100 == 0) || (year % 400 = 0)))
{
return 29;
}
else
{
return monthArray[month];
}
}
Date GetAfterXDay(int x)
{
//先用一个结果,先生成一个中间临时对象。拷贝d1,this是d1的地址
//Date tmp;
//tmp._year = _year;//传值返回不用tmp,因为tmp出了作用域后被销毁,返回tmp的拷贝。进行拷贝构造
//用同类型对象
//Date tmp(*this);拷贝构造
Date tmp = *this;//拷贝构造
//不能用引用,用引用tmp是d1的别名。tmp的改变就是d1的改变。
//不动自己的成员
//加法进位
tmp._day += x;
while (tmp._day > GetMonthDay(tmp._year, tmp._month))
{
//进位
tmp._day -= GetMonthDay(tmp._year, tmp._month);
++tmp._month;
if (tmp._month == 13)
{
tmp._year++;
tmp._month = 1;
}
}
//获取日期
//return* this;//返回自己,自己的年月日都在往后加,this是这个对象的指针,*this是这个对象//除了作用于还在
return tmp;//局部对象
}
void Print()
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
int main()
{
Date d1(2023, 9, 13);
Date d2 = d1.GetAfterXDay(100);
d1.Print();
d2.Print();//这时改变_year等会改变d1
return 0;
}
+(不改变)和+=(改变)返回值的区别。