一 构造函数
1.1 构造函数的重载和调用
和普通成员一样,构造函数是允许重载的,一个类可以由多个重载的构造函数,在创建对象的时候,根据传递实参的不同来决定调用哪个构造函数。
#include <iostream> using namespace std; class Array { private: int size; //数组的容量 int *data; //数组首地址 public: Array(); //无参构造函数 Array(int s); //有参构造函数 Array(int s,int z); //有两个参数的构造函数 void setVal(int Index,int value); int GetVal(int Index); ~Array(); }; Array::Array() { cout<<"Array的无参构造函数"<<endl; size = 5; data = (int *)malloc(sizeof(int)*size); } Array::Array(int s) //有参构造函数 { size = s; cout<<"Array的有一个参数的构造函数,size ="<<size<<endl; data = (int *)malloc(sizeof(int *)*size); } Array::Array(int s,int z) //有两个参数的构造函数 { size = s; cout<<"Array的有两个参数的构造函数"<<endl; data = (int *)malloc(sizeof(int *)*size); } void Array::setVal(int Index,int value) { data[Index] = value; } int Array::GetVal(int Index) { return data[Index]; } Array::~Array() { cout<<"Array的析构函数"<<endl; if(data != NULL) { free(data); data = NULL; } } int main(int argc, char const *argv[]) { Array a1; //创建对象,自动调用构造函数 for(int i = 0 ; i < 5;i++) { a1.setVal(i,i+1); } for(int i = 0; i < 5;i++) { cout<<a1.GetVal(i)<<" "; } cout<<endl; //Array a2(10); //括号法 //Array a3(10,20); //Array a4 = 100; //等号法 Array a5 = (10,20); return 0; }
注意:使用等号法时要注意,只能调用单个参数的构造函数,
1.2 拷贝构造函数
<1> 概念
class Name(const className &obj),拷贝构造函数也称为赋值构造函数 作用:用一个类去初始化另一个类对象
<2> 拷贝构造函数的调用时机
1> 用一个对象去初始化另一个对象
//Array a6(a2); Array a7 = a1;
2> 当函数形参是一个对象的时候
void print(Array a) { //a.GetVal(0); } print(a1);
3> 函数的返回值是一个对象
#include <iostream> using namespace std; class Array { private: int size; //数组的容量 int *data; //数组首地址 public: Array(); //无参构造函数 Array(int s); //有参构造函数 Array(int s,int z); //有两个参数的构造函数 Array(const Array &obj); void setVal(int Index,int value); int GetVal(int Index); ~Array(); }; Array::Array() { cout<<"Array的无参构造函数"<<endl; size = 5; data = (int *)malloc(sizeof(int)*size); } Array::Array(int s) //有参构造函数 { size = s; cout<<"Array的有一个参数的构造函数,size ="<<size<<endl; data = (int *)malloc(sizeof(int *)*size); } Array::Array(int s,int z) //有两个参数的构造函数 { size = s; cout<<"Array的有两个参数的构造函数"<<endl; data = (int *)malloc(sizeof(int *)*size); } Array::Array(const Array &obj) { //size = obj.size; //data = obj.data; cout<<"Array的拷贝构造函数"<<endl; } void Array::setVal(int Index,int value) { data[Index] = value; } int Array::GetVal(int Index) { return data[Index]; } Array::~Array() { cout<<"Array的析构函数"<<endl; if(data != NULL) { //free(data); data = NULL; } } void print(Array a) { //a.GetVal(0); } Array& Func() { Array a1; return a1; } int main(int argc, char const *argv[]) { Array a1; //创建对象,自动调用构造函数 for(int i = 0 ; i < 5;i++) { a1.setVal(i,i+1); } for(int i = 0; i < 5;i++) { cout<<a1.GetVal(i)<<" "; } cout<<endl; //Array a2(10); //括号法 //Array a3(10,20); //Array a4 = 100; //等号法 //Array a5 = (10,20); //Array a6(a2); //Array a7 = a1; //print(a1); Array a8 = Func(); //Array(); cout<<"***************"<<endl; return 0; }
<3> 深拷贝
#include <iostream> using namespace std; class Array { private: int size; //数组的容量 int *data; //数组首地址 public: Array(); //无参构造函数 Array(int s); //有参构造函数 Array(int s,int z); //有两个参数的构造函数 Array(const Array &obj); void setVal(int Index,int value); int GetVal(int Index); ~Array(); }; Array::Array() { cout<<"Array的无参构造函数"<<endl; size = 5; data = (int *)malloc(sizeof(int)*size); } Array::Array(int s) //有参构造函数 { size = s; cout<<"Array的有一个参数的构造函数,size ="<<size<<endl; data = (int *)malloc(sizeof(int *)*size); } Array::Array(const Array &obj) //深拷贝 { cout<<"Array的拷贝构造函数"<<endl; size = obj.size; data = (int *)malloc(sizeof(int)*size); for(int i = 0 ;i < size;i++) { data[i] = obj.data[i]; } } void Array::setVal(int Index,int value) { data[Index] = value; } int Array::GetVal(int Index) { return data[Index]; } Array::~Array() { cout<<"Array的析构函数"<<endl; if(data != NULL) { free(data); data = NULL; } } int main(int argc, char const *argv[]) { Array a1(10); Array a2(a1); Array a3 = a1; return 0; }
<4> 默认构造函数
#include <iostream> using namespace std; /* 1.一旦提供了无参构造函数,系统不会再提供默认的无参构造函数 2.一旦提供了有参构造函数后,系统将不会再提供默认的无参构造函数 */ class Demo { public: /*Demo() { cout<<"Demo的无参构造函数"<<endl; }*/ /*Demo(const Demo &obj) { cout<<"Demo的拷贝构造函数"<<endl; }*/ Demo(int x) { cout<<"Demo的拷贝构造函数"<<endl; } }; int main(int argc, char const *argv[]) { Demo d1(1); //会调用系统提供的无参构造函数 Demo d2 = d1;//会调用系统提供的拷贝构造函数 //Demo d3;//一旦提供了无参构造函数,系统不会再提供默认的无参构造函数 return 0; }
1.3 析构函数
格式:~类名(); //析构函数:函数名是类名加~,没有返回值
1.3.1 概念
类创建对象时,系统会自动调用构造函数进行初始化工作,同样,销毁对象时,系统会调用析构函数进行资源回收和清理工作,如释放内存,释放句柄,关闭文件等 《注意》:析构函数没有参数,不能被重载,一个类只有一个析构函数,编译器也会自动生成一个默认的析构函数
1.3.2 对象的动态创建和释放
#include <iostream> using namespace std; class Test { public: Test() { cout<<"Test的构造函数"<<endl; } ~Test() { cout<<"Test的析构函数"<<endl; } }; int main(int argc, char const *argv[]) { //Test t1; //栈空间创建对象 /*Test *pt = (Test *)malloc(sizeof(Test)*1); if(NULL == pt) { cout<<"malloc failure"<<endl; } free(pt);*/ Test *pt2 = new Test; //1.申请内存(堆),2自动调用构造函数 delete pt2; //自动调用析构函数 return 0; }
1.3.3 构造函数的参数初始化列表
#include <iostream> using namespace std; class Date { private: int m_year; int m_month; int m_day; public: /*Date() { cout<<"data的构造函数"<<endl; m_year = 1937; m_month = 7; m_day = 7; }*/ Date(int y,int m,int d) { cout<<"Date有参构造函数"<<endl; m_year = y; m_month = m; m_day = d; } }; //对象的初始化列表:1.类对象作为成员变量并且该类没有提供无参构造函数,2.成员变量用const修饰 class Student { private: const int id; Date birth; public: Student(int i,int y,int m,int d):birth(y,m,d),id(i) { cout<<"student的有参构造函数"<<endl; //id = i; } }; int main(int argc, char const *argv[]) { Student s1(1000,1999,1,1); return 0; }
几点说明:
1>初始化列表优选于当前对象的构造函数执行
2> 子对象的构造顺序和其在类中声明的顺序有关,和参数初始化列表初始化的顺序无关
3> 构造函数和析构函数调用的顺序正好相反
1.4 静态成员变量和静态成员函数
(1)静态成员变量
1>在c++中我们可以使用静态成员变量来实现多个对象共享数据的目标,静态成员变量是一种特殊的变量,有static关键词修饰。
#include <iostream> using namespace std; class Student { public: static int count; //静态成员变量,所有对象共享同一个静态成员变量 private: int id; public: Student() { count++; id = count; //count = 1; } static int GetCount() //静态成员函数 { //id++; //静态成员函数只能访问静态成员变量 return count; } void func() { count++; //普通函数可以访问静态成员变量 } }; //静态成员变量一定要在类的外部初始化 int Student::count = 0; int main(int argc, char const *argv[]) { Student s1; Student s2; cout<<s1.count<<endl; cout<<s2.count<<endl; cout<<Student::count<<endl; //静态成员变量可以直接通过类名来访问 cout<<Student::GetCount()<<endl;//静态成员函数可以直接通过类名来访问 cout<<s1.GetCount()<<endl; return 0; }
1.5 友元
概念: 一个类中私有成员变量只能在类的内部访问,不能在类的外部访问,现在,有这么一种机制,友元,借助友元,我们可以在类的外部去访问类内