C++中的构造函数

C++中相比较C中引入了类的概念。创建一个类就必然会用到构造函数

下面来介绍C++中的构造函数的相关知识

一.构造函数的分类和调用

假设定义一个如下的类

class Person{
    private:

    protected:

    public:
        /*
            其他构造方法后面给出
        */

        ~Person(){
            cout<<"析构函数"<<endl;
        }

        double money;
};

①.无参构造函数(默认构造方法,下面给出的代码是我自定义的,默认构造方法是的)

Person(){
            cout<<"无参构造函数"<<endl;
        }

②.有参构造函数

  1.普通构造函数

Person(double newMoney){
            money = newMoney;
            cout<<"有参构造函数"<<endl;
        }

  2.拷贝构造函数(可以观察到拷贝构造函数是采取引用传递的方式,且不允许修改传入对象的值)

Person(const Person & oldMan){
            money = oldMan.money;
            cout<<"拷贝构造函数"<<endl;
        }

二.构造函数的调用

①.隐式法

Person youngManOne;//调用默认构造方法

Person youngManTwo(1000);//调用有参构造方法

Person youngManThree(youngManTwo);//调用拷贝构造方法

注意:不能用 Person p();这样编译器会认为这是一个函数声明即返回Person类对象的函数

此时还可以用匿名对象,匿名对象在本行代码执行结束后就会释放给出示例

int main(){
    Person(1000);//匿名式声明
    cout<<"????"<<endl;
}

执行结果如下,证明上述结论是正确的。

在使用匿名对象时不能使用拷贝构造函数   如果写成 Person (p1)  这种写法等价于 Person p1 对于这个来说明显是一个对象的声明,所以不可以当做一个匿名对象来使用。

②.显式法(类似Java)

Person youngManOne = Person();//调用默认构造方法

Person youngManTwo = Person(1000);//调用有参构造方法

Person youngManThree =Person(youngManTwo);//调用拷贝构造方法

③.隐式类型转换(不常用)

Person p1 = 100;//等价于 Person p1 = Person(100);
Person p2 = p1//等价于 Person p2 = Person(p1);

三.拷贝构造函数调用时机

①.用已经创建好的对象来初始化新的对象(就是上面调用拷贝构造方法的示例)

②.以值传递的方式给函数参数传值

下面是测试代码

void work(Person oldMan){

}
void test2(){
    Person oldMan;
    work(oldMan);
}

int main(){
    test2();
}

测试结果

也就是说先调用无参构造方法创建了一个对象,后来调用work函数后才执行了拷贝构造函数。也就说明以值传递的方式给函数参数传值此时会调用拷贝构造方法。

③.以值方式返回局部对象

测试代码

Person doWork(){
    Person youngMan;
    return youngMan;
}

void test3(){
    Person youngMan = doWork();
}
int main(){
    test3();
}

测试结果

说明同上。证明结果正确。

下面有需要记住的几点:

  1. 如果提供了有参的构造,那么系统就不会提供默认的构造了,但是会提供拷贝构造
  2. 如果提供了拷贝构造函数,那么系统就不会提供其他的构造函数

四.初始化列表式构造函数

构造函数语法:类名(构造函数的参数列表):属性(值or参数), 属性(值or参数)

例子:

#define  _CRT_SECURE_NO_WARNINGS
#include<iostream>
class Number{
	public :
		int aNum;
		int bNum;
		double cNum;
		Number():aNum(10),bNum(30),cNum(50){

		}
		Number(int a, int b, double c):aNum(a),bNum(b),cNum(c){

		}
};
int main(){
	using namespace std;
	Number num1;
	cout << "num1---- aNum:" << num1.aNum << "bNum:" << num1.bNum << "cNum:" << num1.cNum << endl;
	Number num2(1000,4000,8000);
	cout << "num2---- aNum:" << num2.aNum << "bNum:" << num2.bNum << "cNum:" << num2.cNum << endl;
	system("pause");
	return EXIT_SUCCESS;
}

执行结果:

证明初始化列表式是能够对类中的属性进行赋值的。

五.类对象作为成员的案例

代码:

#define  _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
class Phone{
	public:
		string name;
		Phone(){
			cout << "Phone无参构造函数" << endl;
		}
		Phone(string newName):name(newName){
			cout << "Phone有参构造函数" << endl;
		}
		~Phone(){
			cout << "Phone析构函数" << endl;
		}
};
class App{
	public:
		string name;
		App(){
			cout << "App无参构造函数" << endl;
		}
		App(string newName){
			name = newName;
			cout << "App有参构造函数" << endl;
		}
		~App(){
			cout << "App析构函数" << endl;
		}
};
class Student{
	public:
		App app;
		Phone phone;
		string realName;
		Student(){
			cout << "Student无参构造函数" << endl;
		}
		Student(string appName, string phoneName, string stuRealName) :app(appName),phone(phoneName),realName(stuRealName){
			cout << "Student有参构造函数" << endl;
		}
		~Student(){
			cout << "Student析构函数" << endl;
		}
};

void use(){
	Student stu("FaceBook", "8848", "张喜文");
	cout << stu.realName << "在" << stu.phone.name << "上使用" << stu.app.name << endl;
}
int main(){
	use();
	system("pause");
	return EXIT_SUCCESS;
}

执行结果:

执行分析

可以观察出若一个类中有其他类的对象,构造顺序是先构造其他类的对象,然后构造自己,析构函数则是先执行本类中的析构函数,最后再执行属性类的析构函数。即析构执行顺序与构造的顺序相反

explicit关键字

作用:防止构造函数中的隐式类型转换

例子:

#define  _CRT_SECURE_NO_WARNINGS
#include<iostream>
class Number{
public:
	int aNum;
	Number(){

	}
	explicit Number(int num){
		aNum = num;
	}
};
int main(){
	Number num = 1;
}

执行后结果:证明上述结论正确

猜你喜欢

转载自blog.csdn.net/qq_41313587/article/details/100022480