C ++中类的构造函数是类中不可或缺的一部分。
简单来讲,构造函数的作用是在对象被创建的时候(被自动调用)会利用特定的值构造对象,将对象初始化为一个特定的状态。
更专业地讲:
给创建的对象建立一个标识符; 为对象数据成员开辟内存空间; 完成对象数据成员的初始化。
构造函数也是类的成员函数,但是有它的特殊之处:
1.没有返回值;
2.函数名与类名相同
这里重点讲一下特殊的构造函数,复制(拷贝)构造函数:
如
Point::Point(Point& p){ x = px; y = py; }
拷贝构造函数的用处:
如图1所示,用已知的对象创建同一个类的新对象。
main(){ Point b(a); // Point b = a; }
2,在使用对象作为函数参数时,当实参值传递给形参时,系统将自动调用拷贝构造函数来实现这一传递。
void fun(Point p){ cout << p.getX() << endl; }
main(){ Point a(1,2); f(a); }
此处注意细节:
把对象使用值传递时(参数为副本对象)才会调用复制构造函数,传递参数为对象的引用时则不会调用复制构造函数。
所以,在传递比较大的对象时,传递引用会比传值效率高很多。
3,当对象作为函数的返回值时,系统自动调用拷贝构造函数用返回值或对象值创建一个临时对象,然后再将这个临时对象赋值给调用函数中的某个接收函数返回值的对象。
Point g(){ Point a(1,2); return a; }
main(){ Point b; b = g(); }
为什么此时会调用复制构造函数呢?
表面上函数g将a返回给了主函数,但是a是g()的局部对象,离开它的函数g以后就消亡了,不可能在返回主函数中继续生存。
在这种情况下,编译系统会在主函数中创建一个无名的临时对象,该临时对象的生存期只在函数调用所处的表达式中,也就是表达式
b=g()
执行语句
return a;
时,实际上是调用复制构造函数将a的值复制到临时对象中。函数g运行结束时对象a消失,但是临时对象会存在于表达式
b=g()
中。计算完这个表达式后,临时对象的使命也就完成了,该临时对象便自动消失。
下面来说说两类拷贝构造函数:深拷贝和浅拷贝
浅拷贝包括系统默认的和程序员自定义的拷贝构造函数。
如
class Rect { public: Rect(){ count++; } Rect(const Rect& r){ width = r.width; height = r.height; count++; //通过自定义浅拷贝构造函数,新添拷贝构造函数的新功能。 } ~Rect(){ count--; } static int getCount(){ return count; } private: int width; int height; static int count; };
浅拷贝在类里面有指针成员的情况下只会复制指针的地址,会导致两个成员指针指向同一块内存,这样在要是分别delete释放时就会出现问题。
#include <iostream> using namespace std; class Test_class { public: Test_class(int b,char* cstr){
a=b; str=new char[b]; strcpy(str,cstr); } Test_class(const Test_class& T) { a=T.a; // str = T.str; //浅拷贝 str=new char[a]; if(str!=NULL) strcpy(str,T.str); } void Show() { cout<<str<<endl; } ~Test_class() { delete str; } private: int a; char *str; }; int main() { Test_class A(10,"C++ world!"); Test_class B=A; //调用拷贝构造函数,与Test_class B(A)相同。 return 0; }
//如果使用浅拷贝,则会使得对象 A 与 B的str的地址(发生复制)相同,这样在调用B的析构函数后会先把存储str的内存释放了,此时A对象的str指针就没有了确定的指向,即成为了野指针,这是非常危险.
//此时应该使用深拷贝,即应先给对象A的str指针分配与对象B的str指针指向的内存空间一样大小的内存空间,然后再使用strcpy等函数将内容拷贝给A的str指针所指向的地址的内容
B.Show(); return 0; }
很明显的,如果没有没有创建内存只赋值为浅拷贝,创建新内存把值全部拷贝一份就是深拷贝。
浅拷贝和深拷贝主要区别就是复制指针时是否重新创建内存空间。
最后附上C++两个文件,挺经典的,用到了运算符的重载。
#include<iostream> #include<cstring> using namespace std; class mystring { public: mystring(const char* newstr=0); mystring(const mystring& other); ~mystring(); mystring& operator=(const mystring& m); char operator[](int index); void operator+=(mystring &c); friend ostream& operator<<(ostream& out, const mystring& d); void show(){ cout << str << endl; } int getlen(){ return strlen(str); } private: char* str; }; mystring::mystring(const char* newstr) { if(newstr) { int len=strlen(newstr); str=new char[len+1]; strcpy(str,newstr); } else { str = new char[1]; *str='\0'; } } mystring::mystring(const mystring& other){ int len=strlen(other.str); str=new char[len+1]; strcpy(str,other.str); } mystring::~mystring(){ delete[] str; } mystring& mystring::operator=(const mystring& m){ int len=strlen(m.str); str=new char[len+1]; strcpy(str,m.str); } char mystring::operator[](int index){ return str[index]; } void mystring::operator+=(mystring& c){ char* p=str; int len = getlen()+c.getlen()+1; str = new char[len]; strcpy(str,p); // 函数原型char * __cdecl _strset_l(char *_Str,int _Val,_locale_t _Locale) strcat(str,c.str); delete[] p; } ostream& operator<<(ostream& out, const mystring& d){ out << d.str << endl; return out; } int main() { mystring s1("hello,"),s2("world!"); cout << "s1 first: " << endl; s1.show(); cout << "s2 first: " << endl; s2.show(); mystring s3=s2; cout << "s3=s2,s3: " << endl; s3.show(); s1+=s2; cout << "s1+=s2,s1: " << endl; s1.show(); cout << "s1[2]:" << s1[2] << endl; return 0; }
以及
#include<iostream> using namespace std; class point { public: point(int newx=0, int newy=0):x(newx),y(newy){ } friend ostream& operator<<(ostream& out, const point& p); void setpoint(int newx, int newy); private: int x,y; }; ostream& operator<<(ostream& out, const point& p) { out << "(" << p.x << "," << p.y << ")" ; return out; } void point::setpoint(int newx, int newy) { x = newx; y = newy; } class arrayofpoints { public: arrayofpoints(int newsize):mysize(newsize){ points = new point[mysize]; } ~arrayofpoints() { cout << "delete!" << endl; delete[] points; } arrayofpoints(arrayofpoints& other); arrayofpoints& operator=(const arrayofpoints &a); point& operator[](int index); private: point* points; int mysize; }; arrayofpoints::arrayofpoints(arrayofpoints& other) { cout << "copy!" << endl; mysize = other.mysize; points = new point [mysize]; for(int i=0; i<mysize; i++){ points[i] = other.points[i]; } } arrayofpoints& arrayofpoints::operator=(const arrayofpoints& a){ if(points!=NULL) //由于已经调用了拷贝构造函数,所以已经申请并且释放了内存,此时应判断是否进行了内存的释放 delete[] points; mysize = a.mysize; points = new point[mysize]; for(int i=0; i<mysize; i++) points[i] = a.points[i]; } point& arrayofpoints::operator[](int index) //返回point的引用 { return points[index]; } int main() { arrayofpoints a(1),b(2); //调用arrayofpoints构造函数 ,分别new数组points[1],points[2]; a[0].setpoint(1,1); //调用arrayofpoints类对“[]”的重载函数,返回points[0]; b[0].setpoint(2,2); b[1].setpoint(3,3); cout << "a数组的点为:" << a[0] << endl; //调用point类对<<的重载函数(cout,point&) cout << "b数组的点为:" << b[0] << "," << b[1] << endl; a=b; cout<<"a=b,a数组的点为:"<<a[0]<<","<<a[1]<<endl; return 0; }
有不足之处,还请大家指正!