缺省的构造函数和析构函数,等于放弃了自己初始化和清除的机会;缺省的拷贝构造和缺省的赋值函数,采用“位拷贝和值拷贝”。若类中出现指针时,这两个函数出错。
class String
{
public:
String(const char *str = NULL);//构造
~String();//析构
String (const String &s);//拷贝构造
String& operator=(const String &s);//赋值
String* operator&();//普通引用方法
String* operator&()const;//常引用方法
private:
char* m_str;
};
构造函数与析构函数
构造函数和析构函数表明了一个对象的由生到死的过程。一个对象只能调用一次构造方法,一个类有且只有一个析构方法。
构造函数作用:
1、实例化对象 2、对对象成员进行初始化 3、强制类型转化(通过中间桥梁实现)
#
类的数据成员的初始化方式(二者效率不同)
1、初始化列表方式
2、函数体内赋值
3、类的const 常量只能在初始化列表内初始化,不能在函数体内进行赋值。
#
构造顺序
1、遇到对象自动调用其构造方法,如若有继承关系时,则先调用父类的构造方法;当主函数中构造对象完成时自动调用析构函数。
2、先构造者后析构,因为构造函数中,对象是通过堆栈的方式进行存储的,同理 析构时按照出栈的顺序。
成员对象初始化的次序完全不受他们在初始化列表中的次序,只与成员对象在类中的声明次序有关。
#include<iostream>
using namespace std;
class Test
{
public:
Test()
{
cout<<this<<endl;//6c
}
Test(int d,int num):number(num),data(d)
{
cout<<this<<endl;//64
cout<<"data-->"<<this->data<<endl;
cout<<"number-->"<<this->number<<endl;
}
~Test()
{
cout<<"~Test()"<<this<<endl;
}
private:
int data;
int number;
};
void main()
{
Test t;
Test t2(1,2);
}
强制类型转化
#include<iostream>
using namespace std;
class Test
{
public:
Test()
{
cout<<"Test()"<<this<<endl;
}
Test(int d):data(d)
{
cout<<"Test()"<<this->data<<endl;
}
/*int GetData()const
{
return data;
}
*/
operator int()
{
return data;
}
~Test()
{
cout<<"Free Test()"<<this<<endl;
}
private:
int data;
};
void main()
{
//Test t1(); 声明函数,能编译、能运行,但是是错误的
Test t(1);
t =100;//100通过构建函数构造中间零时对象,对象给对象赋值
//若构造函数前面加上explicit关键字时,则赋值时必须显示调用即 t =(Test) 100;
int value;
//通过公有方法获取data值
//value = t.GetData();
//调用operator int()方法,将对象类型强制转换为值类型
value = t;
}
构造函数,有两种方式:
1、定义无参构造函数 2、定义所用带默认值的构造函数 且 二者方式只能用一种。一个类只能有一个带默认值的构造函数。不然程序产生二义性。当带默认值的参数,没有初始化时,则产生随机值。
#include<iostream>
using namespace std;
class Test
{
public:
//无参构造
Test()
{}
Test(int d):data(d)
{
cout<<data<<endl;
}
//带默认值的构造
/*
Test(int d=0)
{
data = d;
cout<<data<<endl;
}
*/
private:
int data;
};
void main()
{
Test t(2);
}
拷贝构造与赋值函数
拷贝构造函数:用一个已有对象去初始化一个新的对象。
产生拷贝构造的条件:
1、用已有对象去初始化新的对象
2、函数参数类型传递
3、函数返回值类型的对象。
include<iostream>
using namespace std;
include<vld.h>
class Test
{
public:
Test()
{}
Test(int d):data(d)
{}
void print()
{
cout<<data<<endl;
}
//不用引用,自己解释自己会产生循环递归
Test(const Test &other)
{
data = other.data;
}
~Test()
{
cout<<"~Test()"<<endl;
}
private:
int data;
};
void fun(Test s1)
{
cout<<"fun()"<<endl;
}
Test fn()
{
Test s2(1);
//返回s2之前会产生无名的临时对象,即用s2去构造对象 因此调用拷贝构造函数
return s2;
}
void main()
{
Test t(2);
//两者一样
//Test t1(t);
Test t1= t;
t.print();
t1.print();
//对象作为函数参数
fun(t1);
//对象作为函数的返回值
t=fn();
}
return 返回时,实际调用了拷贝构造函数构造了一个无名的临时对象
int Sum(int a,int b)
{
return sum=a+b;
//返回的不是sum,sum在离开作用域时,已经被释放;会产生一个临时无名对象,并将sum 值传给该对象。
}
void main()
{
int val=Sum(1,2);
}
赋值
赋值相当于a对象的成员参数,给b的成员参数赋值。
1、是否把返回值的类型声明为该类型的引用。
2、是否把传入的参数声明为常量引用。
3、是否释放自己已有空间。
4、是否判断传入的参数和当前的实例(*this)是不是一个实例。
#
#include<iostream>
using namespace std;
#include<vld.h>
class Test
{
public:
Test(int d=0):data(d)
{}
void print()
{
cout<<data<<endl;
}
Test(const Test &other)
{
data = other.data;
}
/*
1.const:表明对象的数据成员在赋值过程中,不被修改
2.&s:减少调用一次拷贝构造函数,也提高效率,在程序中,当对象不受函数作用域的影响时,可以使用&
3.Test 为了是连续对象间赋值t1=t2=t3;
4.在返回类的对象*this时,会产生临时对象调用拷贝构造函数。&为了不构造临时对象,减少调用拷贝构造
t1.operator=(t2.operator=(t3))
*/
Test& operator=( const Test &s)
{
if(this != &s)
{
data = s.data;
}
//返回当前对象
return *this;
}
~Test()
{
cout<<"~Test()"<<endl;
}
private:
int data;
};
void main()
{
Test t(10);
Test t1(t);
Test t2;
t2 = t1;
//t2.operator=(t1)
//t2.operator=(&t2,t1)
//下面的const用来说明当前对象不允许修改
//Test& operator(Test *const this,const Test &s )
}
普通引用方法与常引用方法
#include<iostream>
using namespace std;
#include<vld.h>
class String
{
public:
String(char *str=NULL)
{
//构造的对象为NULL时,String a(""|NULL|0)和String a()不一样
if(str == NULL)
{
m_str = new char[1];
*m_str = '\0';
}
else
{
m_str = new char[strlen(str)+1];
strcpy(m_str,str);
}
}
//深拷贝
String(const String &s)
{
m_str = new char[strlen(s.m_str)+1];
strcpy(m_str,s.m_str);
}
//深赋值
String& operator=(const String &other)
{
if(this != &other)
{
String tmp=other;
char *pstr=m_str;
m_str= tmp.m_str;
tmp.m_str = pstr;
}
return *this;
}
//普通引用方法
String* operator&()
{
return this;
}
//常方法
const String* operator&()const
{
return this;
}
~String()
{
delete []m_str;
m_str = NULL;
}
private:
char *m_str;
};
void main()
{
String s("123");
String s1=s;
String s2;
s2=s1;
String *p =&s1;
const String s3("Hello");
const String *q =&s3;
}