目录
class Date {}; //空类
- class Date
- {
- public:
- void Init(int year, int month, int day)
- {
- _year = year;
- _month = month;
- _day = day;
- }
- void Print()
- {
- cout << _year << "-" << _month << "-" << _day << endl;
- }
- private:
- int _year;
- int _month;
- int _day;
- };
- int main()
- {
- Date d1;
- d1.Init(2022, 7, 5);
- d1.Print();
- Date d2;
- d2.Init(2022, 7, 6);
- d2.Print();
- return 0;
- }
- class Date
- {
- public:
- // 1.无参构造函数
- Date()
- {}
- // 2.带参构造函数
- Date(int year, int month, int day)
- {
- _year = year;
- _month = month;
- _day = day;
- }
- private:
- int _year;
- int _month;
- int _day;
- };
- void TestDate()
- {
- Date d1; // 调用无参构造函数
- Date d2(2015, 1, 1); // 调用带参的构造函数
- // 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
- // 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象
- // warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意用变量定义的?)
- Date d3();
- }
- class Date
- {
- private:
- // 基本类型(内置类型)
- int _year = 1970;
- int _month = 1;
- int _day = 1;
- // 自定义类型
- Time _t;
- };
- class Date
- {
- public:
-
- //无参的构造函数
- Date()
- {
- _year = 1900;
- _month = 1;
- _day = 1;
- }
-
- //全缺省的构造函数
- Date(int year = 1900, int month = 1, int day = 1)
- {
- _year = year;
- _month = month;
- _day = day;
- }
- private:
- int _year;
- int _month;
- int _day;
- };
析构函数是特殊的成员函数,其特征如下:
以下为栈的实现
- #include
- using namespace std;
- #include
- #include
-
-
- typedef int DataType;
-
- struct Stack
- {
- public:
- void Init()
- {
- _array = (DataType*)malloc(10 * sizeof(DataType));
- if (NULL == _array)
- {
- assert(false);
- return;
- }
- //没上面问题容易给3,数量为0
- _capacity = 10;
- _size = 0;
- }
-
- //入栈
- void Push(DataType data)
- {
- _array[_size] = data;
- ++_size;
- }
- //出战
- void Pop()
- {
- if (Empty())
- return;
-
- _size--;
- }
- //获取栈顶元素
- DataType Top()
- {
- assert(!Empty());
- return _array[_size - 1];
- }
- bool Empty()
- {
- return 0 == _size;
- }
- int Size()
- {
- return _size;
- }
- void Destroy()
- {
- if (_array)
- {
- free(_array);
- _array = nullptr;
- _capacity = 0;
- _size = 0;
- }
- }
-
- private:
- //扩容方法
- void _CheckCapacity()
- {
-
- }
- private:
- DataType* _array;
- size_t _capacity;
- size_t _size;
- };
-
- int main()
- {
- Stack s;
- s.Init();
- s.Push(1);
- s.Push(2);
- s.Push(3);
- s.Push(4);
- s.Push(5);
-
- cout << s.Top() << endl;
- cout << s.Size() << endl;
-
- s.Pop();
- s.Pop();
- cout << s.Top() << endl;
- cout << s.Size() << endl;
-
- s.Destroy();
- return 0;
- }
因为我们代码中自己写了初始化 Init 和 Destory,所以在主函数中你要进行栈操作,必须手动加上s.Init();以及s.Destroy(); 要是不加就会崩溃,这样的话你总有失误的时候,此时我们想让栈创建好就有空间,所以对代码需要优化,下面为部分优化代码
- ~Stack()
- {
- if (_array)
- {
- free(_array);
- _array = nullptr;
- _capacity = 0;
- _size = 0;
- }
- }
- void TestStack()
- {
- Stack s;
- s.Push(1);
- s.Push(2);
- s.Push(3);
- s.Push(4);
- s.Push(66);
-
- cout << s.Top() << endl;
- cout << s.Size() << endl;
-
- s.Pop();
- s.Pop();
- cout << s.Top() << endl;
- cout << s.Size() << endl;
- }
- int main()
- {
- TestStack();
- return 0;
- }
注意:像Date类一样,对象中没有涉及到任何资源管理时,该类的析构函数可以不必给出
- class Date
- {
- public:
- Date(int year = 1900, int month = 1, int day = 1)
- {
- _year = year;
- _month = month;
- _day = day;
- }
- void Print()
- {
- cout << _year << "/" << _month << "/" << _day << endl;
- }
-
- ~Date()
- {
- cout << "~Date():" << this << endl;
- }
- private:
- int _year;
- int _month;
- int _day;
- };
- void TestDate()
- {
- Date d(2022, 11, 22);
- }
- int main()
- {
- void TestDate();
- return 0;
- }
- Date(const Date& d)
- {
- _year = d._year;
- _month = d._month;
- _day = d._day;
- }
-
- Date d2(d1);
错误例子如下:如果这样使用,会不断的调用拷贝,这就是传值引发对象的拷贝
Date(const Date& d)

问题:编译器生成的拷贝构造,虽然没有生成但是可以完成拷贝构造的工作,既然编译器已经可以完成了,那拷贝构造函数还需要用户自己写吗?、
答:像日期这种没有涉及到资源管理时, 可写可不写,一般不写,因为编译器可以完成拷贝的工作,如果需要自己再去实现,注意编译器是按照值的方式拷贝的---即:将一个对象中的内容原封不动的拷贝到另一个对象中(浅拷贝)
对上面所有内容用一段代码进行对比总结,代码如下:
- #include
- using namespace std;
- #include
- #include
-
- class Date
- {
- public:
- Date(int year = 2000, int month = 1, int day = 1)
- {
- _year = year;
- _month = month;
- _day = day;
- cout << "Date(int,int,int):" << this << endl;
- }
- Date(const Date& d)
- {
- _year = d._year;
- _month = d._month;
- _day = d._day;
- cout << "Date(const Date& d):" << this << endl;
- }
- ~Date()
- {
- cout << "~Date():" << this << endl;
- }
- private:
- int _year;
- int _month;
- int _day;
- };
- void TestDate1()
- {
- //只要创建对象,就必须调用构造函数
- //拷贝构造是:用已经存在的对象构造新对象时调用
- //其余创建新对象的场景调用的基本都是构造函数
-
- Date d1(2022,11,15);//构造函数
-
- //用已经存在的对象创建,拷贝构造函数调用场景1
- Date d2(d1);
- }
-
- //拷贝构造函数调用场景2:以值的方式传参
- void TestDate2(Date d)
- {
- Date dd;
- }
-
- //拷贝构造函数调用场景3:以值的方式返回对象
- Date TestDate3()
- {
- Date d;
- return d;
- }
-
- int main()
- {
- Date md;
- TestDate1();
- TestDate2(md);
- TestDate3();
- return 0;
- }

分析:按上图几行来说明
第一,二行首先就是运行TestDate1 ,运行d1和调用Date
第三行,运行d2,进行了拷贝构造,调用了拷贝构造函数
第四行第五行进行析构函数销毁,因为是栈,先创建的后销毁,所以先销毁d2,在销毁d1
第六行运行TestDate2,拷贝构造md,在运行构造函数其中的dd,之后均析构销毁
TestDate3先构造d,在要以值的方式返回的时候,不能返回d,因为函数结束会销毁,所以只能借助拷贝构造函数在返回之前先创建临时对象,返回临时对象
注意:
// 1. 以值的方式返回时,如果返回的是匿名对象,则编译器不会再用匿名对象
// 拷贝构造临时对象,而是直接将匿名对象返回了
// 匿名对象:没有名字的对象
// 2. 如果参数是以值的方式传递,实参如果也是匿名对象,也会少一次拷贝构造
// 3. 在C++中,参数能使用引用尽量使用引用,如果不想通过形参改变外部的实参,尽量设置为const类型的引用
