构造函数是怎样的
-
函数名和类名相同
class MM /*写出来的函数就不是默认构造函数了(看不到),虽然无参,但是和默认的不一样*/
{
public:
MM() //无参构造函数
{
}
void MM() //报错:与其类具有相同名称的成员函数一定是构造函数
{
}
};
-
没有返回值 - - - 没有类型
void print(); //这个函数有返回值,返回值是void 构造函数无返回值指: 没有void这个类型
- 当我们自己写了构造函数,默认的构造函数就不存在了→ 不能构建无参的对象[构造对象的过程就是调用这个函数的过程]
- 参数无要求,默认的构造函数是无参的
构造函数的作用
-
构造函数在构造对象时调用,不需要自己手动调用,(就是用来构造对象的)
-
构造函数更多是用来初始化数据成员
-
想要构造什么长相的对象,必定需要什么长相的构造函数
新关键字:默认构造函数可以被删掉
MM() = delete; //delete可以用来删掉默认的无参函数
小知识:
-
为什么不写构造函数可以构造对象?
是因为存在一个默认的无参构造函数,所以可以构造无参对象
-
构造函数重载、缺省是为了什么?
为了构造不同长相的对象(有参、无参、1个参数、多个参数...)
常见报错:没有与之匹配的构造函数,一般是由于没有写构造函数造成的
class MM
{
public:
MM() = delete; //删掉默认的构造函数
void print()
{
cout << name << " " << age << endl;
}
protected:
string name="小明";
int age=18;
};
int main()
{
MM mm; /*删掉默认构造函数后,无法构造无参对象-->报错: 无法引用MM的默认
构造函数,它是已删除的函数*/
mm.print();
}
带参构造函数
class MM
{
public:
MM(string mmName, int mmAge)
{
name = mmName;
age = mmAge;
cout << "带参构造函数" << endl;
}
};
int main()
{
MM mm("小明",22); /*有2个参数的对象(想构造无参的对象,需要无参构造
函数,提供一个无参构造函数即可)
}
无参构造函数
方式1
class MM
{
public:
MM()
{
cout << "无参构造函数" << endl;
}
};
方式2 (比自己写的无参构造函数快)
class MM
{
public:
MM() = default; //指定使用默认的无参构造函数,用default说明
};
int main()
{
MM mm; //提供无参构造函数,从而构造无参对象(构造无参对象,需要无参构造函数)
}
关于函数重载、缺省可以看看这篇博客的部分内容:c和c++的区别(一)_考拉爱睡觉鸭~的博客-CSDN博客
函数重载 (需要写3个函数、缺省的方式一个函数 等效可以实现下面三个函数的功能)
class MM
{
public:
MM() {}
MM(string mName)
{
name = mName;
}
MM(string mName, int mage)
{
name = mName;
age = mage;
}
protected:
string name;
int age;
};
int main()
{
MM mm1;
MM mm2("小明");
MM mm3("小李", 18);
}
函数缺省 (缺省两个参数、一步到位)
class MM
{
public:
MM(string mname="", int mage=25)
{
name = mname;
age = mage;
}
protected:
string name;
int age;
};
int main()
{
MM mm1;
MM mm2("小明");
MM mm3("小李", 18);
}
初始化参数列表的方式---只有构造函数有
方式
构造函数名(参数1,参数2,. . .) :数据成员1(参数1),数据成员2(参数2),. . .( ){ }
把参数1赋给数据成员1...以此类推
作用
避免形参名和数据成员名相同导致的问题
允许构造函数调用另一个构造函数,必须采用初始化参数的写法,继承、类的组合中会用到
class MM
{
public:
MM(string mname="", int mage=18):name(mname),age(mage)/*mname给name初始化,
形参给数据成员初始化*/
{
cout << "初始化参数列表" << endl;
}
protected:
string name;
int age;
};
初始化参数列表不一定要按顺序写(一般按顺序写、参数多了容易漏写参数)
class MM
{
public:
MM(string mname="", int mage=18):age(mage),name(mname)
{
cout << "初始化参数列表" << endl;
}
protected:
string name;
int age;
};
小知识:
可以让别的东西初始化吗?不传参,用外部的变量给数据成员初始化也行
(只要是一个值,且和要赋值的内容类型相同即可)
string mmName = "大白";
class MM
{
public:
MM(int mage) :name(mmName), age(mage) {}
protected:
string name;
int age;
};
可以避免形参名和数据成员名相同导致的问题
class MM
{
public:
MM(string name, int age) :name(name), age(age) {}/*名字相同也能初始化参数列表,
编译器能自动分辨*/
void print()
{
cout << name << "\t" << age << endl;
}
protected:
string name;
int age;
};
委托构造
构造函数调用另一个构造函数初始化数据
class MM
{
public:
MM(string name, int age):name(name), age(age) {}
// MM(){}; 无参构造函数,和默认构造函数不同,没有给数据做初始化输出是垃圾值
MM():MM("默认",18){} /*委托构造: c++11新标准--->允许构造函数调用另一个构造函数
给数据初始化 调用上面的构造函数MM给数据初始化*/
void print()
{
cout << name << "\t" << age << endl;
}
protected:
string name;
int age;
};
int main(){
MM mm; //构造一个无参的mm
mm.print();
}
/*输出*/
默认 18