一、构造函数
1、构造函数也是函数的一种, 构造函数的主要任务就是初始化类中成员变量
在C++中,通过一个类去创建对象时,那么编译器会完成两个工作:
1)给对象分配一块内存,类似于int? i
2)C++编译器强行调用构造函数,并且为隐式调用
2、构造函数的语法
特点:
- 构造函数的函数名必须跟类名
- 构造函数无返回值
- 当我们创建类对象的时,构造函数会被自动调用,无需我们主动调用
一个类中,可以有多个构造函数,构造函数之间可构成函数重载的关系
无参构造函数
有参构造函数
class Kitty{
public:
//编译器会默认提供一个无参构造函数,如果手动实现构造函数(无参和有参),则默认就不在提供无参构造函数
//无参构造函数
Kitty()
{
cout << "Kitty()" << endl;
}
Kitty(float weight1 = 0.0)
{
cout << "Kitty(float weight = 0.0)" << endl;
weight = weight1;
}
Kitty(string sex1 = "M",float weight1 = 0.0)
{
cout << " Kitty(string sex1 = "",float weight1 = 0.0)" << endl;
weight = weight1;
sex = sex1;
}
Kitty(string sex1 = "M",string color1 = nullptr,float weight1 = 0.0)
{
cout << " Kitty(string sex1 = "",string color1 = nullptr,float weight1 = 0.0)" << endl;
weight = weight1;
color = color1;
sex = sex1;
}
void printK()
{
cout << "weight = " << weight << sex << color << endl;
}
private:
float weight;
string sex;
string color;
//const int i;
//static int i
//T t;
};
int main()
{
/*
main.cpp:41:11: error: call to constructor of 'Kitty' is ambiguous
main.cpp:11:5: note: candidate constructor
main.cpp:15:5: note: candidate constructor
main.cpp:20:5: note: candidate constructor
main.cpp:25:5: note: candidate constructor
*/
// Kitty cat;
Kitty t1("M",2.0); //ok
t1.printK();
Kitty t2(2.0); //ok
t2.printK();
Kitty t3("W","white",0.2); //ok
t3.printK();
return 0;
}
类对象所占内存的分析:
总结:对于构造函数要记住特点,构造函数在创建对象时,会被调用,主要任务用来初始化成员,除此之外,它跟普通 的成员函数 并没有区别,也可以来实现函数调用,条件判断,循环,赋值等操作,但是,不建议在构造函数中,做过多的逻辑操作。从一定程度上,会导致效率降低。
3、创建类对象的方式
在栈上
在堆上
静态存储区
跟普通类型的变量,并无区别
int i; //在栈上 ---- 在左大括号开始,右大括号结束
在C语言中,利用malloc 和 free函数
type* p = (type*)malloc(sizeof(type))
在C++中,也是有一种更好的解决方案:new/delete运算符
type* 指针变量 = new type; //无参构造函数
type* 指针变量 = new type(参数列表);//有参构造函数
Kitty* pk = new Kitty("W","white",0.2);
pk->printK();
delete pk;
static type i ;
二、拷贝构造函数
类是一种类类型,那么就存在以下这个情况
//定义一个类类型
class Test
{
public:
Test(int m_t)
{
t = m_t;
}
private:
int t;
};
使用:
Test t;
// int i = 10; int j = i; 使用一个变量给另一个声明的变量初始化
Test t1 = t; //如果成立,则表明,确实存在使用一个对象来初始化另一个对象
//而在创建对象t1时,必须会调用构造函数 --- 拷贝构造函数
拷贝构造函数的原型:?
类名(const 类名& anther)
{
成员变量 = anther.成员变量
}
系统会提供一个默认的拷贝构造函数,如果一经手动实现,则系统提供的拷贝构造函数
就不复存在,系统默认提供的拷贝构造函数是一个浅拷贝(简单的用一个对象的成员的值
来给另一个对象的成员进行初始化 比如 t = other.t)
深拷贝:手动重新实现拷贝构造函数简单赋值之外的操作,称之为深拷贝
class Test
{
public:
Test(int m_t = 0)
{
cout << "Test(int m_t = 0)" << endl;
// t = m_t;
// t = new int; //ok
t = (int*)malloc(sizeof(int));
if(t != NULL)
{
*t = m_t;
}
}
//拷贝构造函数
Test(const Test& other)
{
cout << "Test(const Test& other)" << endl;
// t = other.t; 简单的赋值操作,浅拷贝
//重新给指针变量申请堆空间
t = (int*)malloc(sizeof(int));
if(t != NULL)
{
*t = *(other.t);
}
}
void printT()
{
cout << "t = " << *t << endl;
}
//手动实现资源
void Tfree()
{
if(t != NULL)
{
free(t);
t = NULL;
}
}
private:
int* t;
};
int main()
{
Test t1(3); //调用有参构造函数
t1.printT();
Test t2 = t1; //调用拷贝构造函数
t2.printT();
t1.Tfree(); //对象t1释放申请的内存
t2.Tfree(); //对象t2释放申请的内存 同一块内存被第二次释放内存
// double free or corruption (fasttop): 0x0000000001337030 *
//原因在于默认的拷贝是浅拷贝,如果类的成员变量有指针时,拷贝要使用深拷贝
return 0;
}
三、 析构函数
在C++中,类可以定义一个特殊的成员函数清理对象(变量)所占用的资源,该成员函数叫做析构
函数
规则:
- 对象销毁时,自动调用,完成销毁后清理工作(不是清理对象本身,而是清理在使用过资源)
- 无返回值,函数名与类名相同。无参,不可以进行重载和默认参数
语法:
~类名(){ }
//如果在类设计时,没有手动实现析构函数,然而编译器会提供一个默认的析构函数,
//该函数体为空,如果手动实现析构函数,编译器就不会再提供默认析构函数
class 类名
{
public:
//构造函数
类名(参数列表)
{
}
//析构函数
~类名()
{
}
private:
//成员变量
};
以上是一个类设计时的基本模板
四、 构造函数初始化列表
类设计
????????类的成员变量
????????????????基本数据类型变量
????????????????cosnt 修饰的成员变量
????????????????static修饰的成员变量
????????????????类类型成员变量
????????类的成员函数
????????????????构造函数
????????????????析构函数
????????????????功能接口函数
????????????????运算符重载函数
如果类成员变量中有const来修饰的变量,要使用构造函数初始化列表来进行初始化
构造函数初始化列表语法:
构造函数(参数1,参数2,....,参数n):成员变量1(参数1),成员变量2(参数2),...,成员变量n(参数n)
{
}
class Test
{
public:
Test(int t1=0,int t2=0):m_t2(t2)/*,m_t1(t1)*/
{
m_t1 = t1;
// m_t2 = t2; //error
}
void printT()
{
cout << "m_t1 = " << m_t1 << "m_t2 = " << m_t2 <<endl;
}
private:
int m_t1;
//由const修饰的成员变量,该变量是只读,不能通过接口来修改它的值
const int m_t2 ; //如果类成员变量中有const来修饰的变量,要使用构造函数初始化列表来进行初始化,
//不能使用普通的构造函数的方式来初始化它
// const int m_t2 = 100; //ok,但是不推荐它,原因在于,不是所有的C++版本支持此写法,C++11版本才支持
};
int main()
{
Test t;
t.printT();
Test t2(10,20);
t2.printT();
return 0;
}
|