构造函数心田居士

在建立一个对象时,通常最需要立即做的工作是初始化对象,如对数据成员赋初值。为了解决对象初始化的问题,C++提供了构造函数来处理对象的初始化。

(一)

构造函数是一种特殊的成员函数,与其它成员函数不同,它不需要人为调用,而是建立对象时自动被执行。C++规定构造函数的名称与类的名称相同,并且不能指定返回类型。

比如:

Data (int i,int j)          //构造函数

a=i;b=j;

Data ()          //构造函数

a=1;b=2;

定义对象的形式:Data A(1,2);     //定义Data对象A,调用构造函数初始化

Data A;            //构造函数没有形参时候

1)构造函数初始化列表

构造函数可以包含一个构造函数初始化列表:

类名(形参)

:构造函数初始化列表         //初始化阶段

{                                            //计算阶段

函数体

构造函数分为两个阶段进行:初始化阶段与计算阶段。初始化阶段由构造函数初始化列表组成,计算阶段由构造函数函数体的所有语句组成,初始化阶段先于普通的计算阶段。使用初始化列表的构造函数初始化数据成员;而没有定义初始化列表的构造函数版本在函数体中对数据成员赋值。

不管成员是否在构造函数函数初始化列表中显式地初始化,类的成员对象初始化总是发生在计算阶段之前。

关于构造函数初始化列表的几点说明:

a)有时必须使用构造函数初始化列表

如果没有为类类型的数据成员提供初始化表,编译器会隐式使用该成员的默认构造函数。如果没有那个类的默认构造函数,编译器回报错。这种情况下,必须提供初始化列表。

2)构造函数重载与带默认参数的构造函数

Point(){x=y=0;}

Point(int a,int b):x(a),y(b){}

Point m,n(1,2);

系统根据对象建立的形式确定对应的构造函数。

Point(int a=0,int b=0):x(a),y(b){}       //带默认参数的构造函数

Point k ,m(1),n(1,2);

定义k时候没有给出实参,默认为构造函数中的默认参数;同理m(1),形参a=1,b=0。

从上面可以看到在构造函数中使用默认参数方便且有效,它提供了建立对象时的多个选择,作用相当于多个重载的构造函数。

3)默认构造函数

定义对象时没有提供初始化式,就会使用默认构造函数,定义默认构造函数的一般形式:

类名()

函数体

任何类有且只有一个默认构造函数。如果定义的类中没有显示定义任何构造函数,编译器会自动为该类生成默认构造函数,称为合成默认构造函数。合成默认构造函数使用与变量初始化相同的规则来初始化成员。具有类类型的成员通过运行各自的默认构造函数来进行初始化。通常在默认构造函数中给成员提供的初始值应该指出该对象是“空的”,即按二进制位置0。

一个类哪怕只定义一个构造函数,编译器也不会再生成默认构造函数,换言之,如果为类定义一个带参数的构造函数,还想要无参数的构造函数,就必须自己定义它。

一般地,任何一个类都应该定义一个默认构造函数。因为很多情况下,默认构造函数是编译器隐式调用的。下面是一个例子:  class Data{

public:    Data(string str):s1(str){}

private:

string s1;

};

class Data1{

public:    Data1(){}                //错误,Data对象没有合适的默认构造函数可用

private:    Data one;

};

只要Data1类的构造函数初始化列表中没有形如one("hello")之类的初始化式,则Data1类的构造函数总是错的。因为Data1类的构造函数试图使用Data的默认构造函数,但Data没有默认构造函数。

4)隐式类型转换(其他类型转换为类类型)

class Data{

public:

Data(const string& str=""):s1(str){}

void SetString(const Data& r){s1=r.s1;}

private:

string s1;

Data one;

string str="hello";

编译器使用接收string实参的Data构造函数从str生成一个新的Data对象。

public:

explicit Data(const string& str=""):s1(str){}

void SetString(const Data& r){s1=r.s1;}

private:

string s1;

一般地,除非有明显的理由想要定义隐式转换,否则单形参构造函数应该为explicit。将构造函数设置为explicit可以避免错误,如果真需要转换,可以显式构造对象。

(二)复制构造函数

只有单个形参,而且该形参是对本类类型对象的引用常量,这样的构造函数称为复制构造函数:

类名(const 类名 & obj)

例子:

class Point{

public:

Point():x(0),y(0){}                                //默认构造函数

Point(const Point& r):x(r.x).y(r.y){}     //复制构造函数

Point(int a,int b):x(a),y(b){}                 //带参数的构造函数

Point(const string& str);                     //带参数的构造函数

private:

int x,y;

Point:Point(const string& srt)

{      //从“x,y”形式的字符串中解析出x和y

char buf[100];

复制构造函数有且只有一个本类类型对象的引用形参,通常使用const限定。形参声明为引用类型可以减少时间和空间开销,使用const是必需的,因为复制构造函数只是复制对象,没有必要改变传递过来的对象的值。复制构造函数的功能是利用一个已知的对象来初始化一个被创建的同类的对象。

与复制构造函数对应的对象的定义形式为:

类名 对象名(类对象)

Point b(1,2);

Point c(b);

1)合成复制构造函数

每个类必须有一个复制构造函数。如果没有定义复制构造函数,编译器会自动合成一个,称为合成复制构造函数。与合成默认构造函数不同,即使定义了其他构造函数,也会合成复制构造函数

2)何时使用复制构造函数

a)用一个对象显式或隐式初始化另一个对象时,即复制初始化时。

C++支持两种初始化形式,复制初始化与直接初始化。复制初始化使用等号(=),而直接初始化将初始化式放在圆括号中。

当用于类类型对象时,复制初始化与直接初始化是有区别的:直接初始化直接调用与实参匹配的构造函数,而复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数将临时对象复制到正在创建的对象。

Point direct;                //直接调用默认构造函数

Point d(1,3);               //直接调用Point(int a,int b)构造函数

Point copy=Point();   //复制初始化,调用默认构造函数

Point d1="lzb";          //复制初始化,调用Point(const string &str)构造函数

b)函数参数按值传递对象时或函数返回对象时

当函数形参为对象类型,而非指针或引用类型时,函数调用按值传递对象,即编译器调用复制构造函数产生一个实参对象副本传递到函数中。

类似地,当以对象类型作为返回值时候,编译器调用复制构造函数产生一个return语句中的值的副本返回到调用函数。

Point x,y,c;

c=fun(x,y);

c)根据元素初始化式列表初始乎数组元素时

如果没有为类类型数组提供元素初始化式,则将使用默认构造函数初始化每一个元素。然而,如果使用常规的大括号的数组初值列表形式来初始化数组时,则使用复制初始化来初始化每一个元素。

总的来说,正是有了复制构造函数,函数才能传递对象与返回对象,对象数组才能用初值列表的形式初始化。

3)深复制与浅复制

浅复制就是仅仅复制指针变量;深复制是复制指针对应的内容。

(三)总结

1)构造函数的作用是初始化数据成员。如果类的数据成员是const对象,类类型对象,那这些对象的初始化只能在初始化列表中进行。

2)构造函数决定了对象定义时的形式。

3)类有重载的构造函数,或者类带默认参数的构造函数时候,需要注意不能有冲突的构造函数形式。

4)只要自己定义了任何形式的构造函数,则编译器不会合成默认构造函数。如果需要默认构造函数,那需要显式定义无参数的构造函数。

5)除非自己定义复制构造函数,否则类总是会合成一个复制构造函数。复制构造函数的形式为:  类名(const 类名 &obj)

当用一个对象初始化另一个对象,函数参数使用对象,函数返回使用对象或运算中出现临时对象时,要求类必须要有复制构造函数(无论合成还是自定义的)。

6)单个参数的构造函数形式为:

类名(const 指定数据类型是&obj)

可以实现将指定数据类型转换为类类型。

7)对象赋值和对象复制概念上,实现上,形式上是不同的。

对象赋值是对一个已经存在的对象赋值,因此必须先定义被赋值的对象,才能进行赋值。而对象的复制则是从无到有建立一个新对象,并且使它与一个已有对象完全相同(包括对象的结构与成员值)。

对象的赋值是因为类重载了赋值运算符,因为任何类默认都会重载赋值运算符,因此任何类的的对象都可以赋值。对象的复制是因为类有复制构造函数,因此任何类的对象在定义时都可以使用复制初始化,函数形成与返回可以是类对象。

Data a,b;

a=b;                                    //对象赋值

Data c(a),d=b;                    //对象复制

Data fun(Data x,Data y);    //函数原型,对象复制

THE END
0.C++构造函数详解:初始化对象的艺术本文详细介绍了C++中的构造函数,包括其概念、类型(无参、带参及全缺省)、默认构造函数的意义以及C++11中对缺省值的处理。通过实例说明了构造函数如何简化对象初始化过程。 💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 jvzquC41dnuh0lxfp0tfv8qwjcuscw=361gsvrhng1jfvjnnu1746=5943?
1.C++:类的默认成员函数如果一个类中什么成员都没有,简称为空类。空类中什么都没有吗?并不是的,任何一个类在我们不写的情况下,都会自动生成6个默认成员函数。 【默认成员函数概念】:用户没有显式实现,编译器会生成的成员函数称为默认成员函数 其中两个默认成员函数是用来初始化和清理的分别为:构造函数、析构函数 jvzquC41dnuh0lxfp0tfv8|gkzooa=:253>138ftvkimg8igvcomu8655;<25;5
2.构造函数:c++C++ language reference Welcome back to C++ (Modern C++) Lexical conventions Basic concepts Built-in types Declarations and definitions Built-in operators, precedence, and associativity Expressions Statements Namespaces Enumerations Unions Functions jvzquC41oujo0vnetqyph}3eqo5{j6hp1noctjw{1u77z€6c:0gtr
3.C++构造函数和析构函数(Constructors&Destructors)详解C语言由于global object的诞生比程序进入更早点,所以global object的constructor执行的时间更早于程序的进入点,所谓的default constructor就是没有指定任何的参数的constructor,这篇文章主要介绍了C++ 构造函数和析构函数的相关知识,需要的朋友可以参考下+ 目录 GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用!【 如果你想jvzquC41yy}/lk:30pku1ywqitgn1<7278;k:}3jvo
4.构造函数详解类的6个默认的成员函数 构造函数的概念: 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次。 构造函数的特性 函数名与类名相同。 无返回值。 jvzquC41yy}/extpqvk/exr1errvuyqwu/tpvn4eqpyut~hvqt4ivvq
5.Java构造函数具有公共访问级别的构造函数可以在程序的任何部分中使用。 具有私有访问级别的构造函数只能在声明它的同一类中使用。 具有受保护访问级别的构造函数可以在具有在其中声明类的相同包的程序中以及在任何包中的任何后代类内使用。 具有包级访问权限的构造函数可以在声明其类的同一个包中使用。 jvzquC41yy}/y
6.C++拷贝构造函数(复制构造函数)详解当以拷贝的方式初始化一个对象时,会调用一个特殊的构造函数,就是拷贝构造函数(Copy Constructor)。 下面的例子演示了拷贝构造函数的定义和使用: #include<iostream> #include<string> usingnamespacestd; classStudent{ public: Student(stringname="",intage=0,floatscore=0.0f);//普通构造函数 jvzquC41e0hjcwhjgpm/pny1xkkx1;8560nuou
7.PHP:构造函数和析构函数Please be aware of when using __destruct() in which you are unsetting variables Consider the following code: ; } function__destruct() { if($this->error_reporting===true)$this->show_report(); unset($this->error_reporting); jvzquC41yy}/rqu0pgz0njsiwcmf0xtr70jfexs
8.构造函数(C++)|MicrosoftLearn如果类未定义移动构造函数,则在没有用户声明的复制构造函数、复制赋值运算符、移动赋值运算符或析构函数时,编译器会生成隐式构造函数。 如果未定义显式或隐式移动构造函数,则原本使用移动构造函数的操作会改用复制构造函数。 如果类声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数会定义为已删除。jvzquC41fqit0vnetqyph}3eqo5{j6hp1evq1lur1euou}wwevusu6hrr
9.C++构造函数详解:一篇搞懂所有构造函数知识(含代码+图解)当你没有定义任何构造函数时,编译器会自动生成一个“空的默认构造函数”。 classStudent{ public: intage; }; intmain(){ Student s;// 默认构造函数被调用(编译器生成) s.age =20; } AI写代码cpp 运行 但如果你一旦写了带参数的构造函数,编译器就不会再生成默认构造函数了,你需要手动写一个! jvzquC41dnuh0lxfp0tfv8|gkzooa?:2:2>9:8ftvkimg8igvcomu866;66:9<=
10.C++——构造函数构造函数是C++中一种特殊的成员函数,它在创建类对象时自动调用,用于初始化对象。 构造,那构造的是什么呢? 构造成员变量的初始化值,内存空间等 一、构造函数的基本概念 定义:构造函数是与类同名的特殊成员函数 特点: 没有返回类型(连void都没有) 创建对象时自动调用 通常声明为public(除非有特殊需求) 可以重载(一个类可以有多个构 jvzquC41dnuh0lxfp0tfv8|gkzooa?6448:548ftvkimg8igvcomu86692617A8
11.JAVA中的构造函数(方法)java这篇文章主要介绍了JAVA中的构造函数(方法),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教+ 目录 一、什么是构造函数 Java构造函数,也叫构造方法,是JAVA中一种特殊的函数。与函数名相同,无返回值。 作用:一般用来初始化成员属性和成员方法的,即new对象产生后,就调用了对象的属性和方法。jvzquC41yy}/lk:30pku1ywqitgn1<6:687cov3jvo
12.C++超详细讲解构造函数C语言可以看到使用编译器生成的默认构造函数我们的日期仍然是随机值。 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 jvzquC41yy}/lk:30pku1jwvkerf1;:2448/j}r
13.构造函数前面的示例显示了初始化新对象的实例构造函数。 类或结构还可以声明静态构造函数,该构造函数初始化类型的静态成员。 静态构造函数是无参数的。 如果未提供静态构造函数来初始化静态字段,C# 编译器会将静态字段初始化为默认值,如C# 类型的默认值文章中所列。 jvzquC41oujo0vnetqyph}3eqo5{j6hp1noctjw{1cif7qg|j0gtr
14.构造函数(C++)|MicrosoftLearn如果类未定义移动构造函数,则在没有用户声明的复制构造函数、复制赋值运算符、移动赋值运算符或析构函数时,编译器会生成隐式构造函数。 如果未定义显式或隐式移动构造函数,则原本使用移动构造函数的操作会改用复制构造函数。 如果类声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数会定义为已删除。jvzquC41fqit0vnetqyph}3eqo5{j6HP1evq1lur1euou}wwevusu6hrrA|jg€Bouxi.3=5
15.构造函数前面的示例显示了初始化新对象的实例构造函数。 类或结构还可以声明静态构造函数,该构造函数初始化类型的静态成员。 静态构造函数是无参数的。 如果未提供静态构造函数来初始化静态字段,C# 编译器会将静态字段初始化为默认值,如C# 类型的默认值文章中所列。 jvzquC41oujo0vnetqyph}3eqo5{j6hp1noctjw{1cif7qg|j
16.构造函数基实例构造函数运行。以 Object.Object 开头从每个基类到直接基类的任何实例构造函数。 实例构造函数开始运行。 该类型的实例构造函数运行。 对象初始值设定项运行。 如果表达式包含任何对象初始值设定项,则它们在实例构造函数运行后运行。 对象初始值设定项按文本顺序运行。 使用new 运算符创建实例时,将执行上述操作。 jvzquC41fqit0vnetqyph}3eqo5{j6hp1fuupny1eunbty4rtqmscvrkpi3hwrig1erbu|ju/cte/|ytwezt1ltpuvxve}ttu
17.C++的6种构造函数c++构造函数以值方式返回局部对象(由于编译器的RVO【返回值优化】,所以不会返回对象时不会调用拷贝构造) 构造函数调用规则:默认情况下,编译器会给类至少添加三个函数:默认构造、拷贝构造、析构函数。如果自定义了有参构造,就不再提供无参构造,但会提供拷贝构造;如果自定义了拷贝构造,就不再提供其他构造函数。 jvzquC41dnuh0lxfp0tfv8|gkzooa=:3:8:378ftvkimg8igvcomu86626>86;5