一、.初始化:
对象的初始化使用构造函数
构造函数
构造函数:主要作用在于创造对时为对象的成员属性(成员变量)赋值,构造函数由编译器自动调用,无需手动调用
语法:类名(){}
1.构造函数没有返回值,函数名前也不用写void
2.函数名与类名相同
3.构造函数可以有参数,因此可以发生重载
4.程序在调用对象的时候会自动调用构造函数,无需手动调用,而且只会调用一次
5.当已经提供了有参构造时,程序不会提供无参构造(若此时调用无参构造,程序报错,须程序员手动提供无参构造)
#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;
class A {int* p;
public:A()//构造函数,函数名与类名相同,没有返回值,函数名前不用写void,//如果没有实现构造函数编译器会提供默认的构造函数{cout << "默认构造" << endl;}A(int n) {if (n != 0) {p = new int[n];cout << "使用构造函数在堆区申请了n个int类型的变量" << endl;}}
};
int main() {A p;//输出:默认构造。在创建对象时编译器会帮我们自动调用构造函数,无需手动调用A p1(2);//输出:使用构造函数在堆区申请了n个int类型的变量。调用有参构造创造对象A p2();//输出: 编译器会把它认为是函数声明,A是返回值类型,p2是函数名,()是函数参数return 0;
}
构造函数的分类及调用:
分类:
1.按照参数分:有参构造和无参构造
2.按照类型分:普通构造和拷贝构造
调用方式:
1.括号发
2.显示法
3.隐式转换法
#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;
class A {int* p;
public:A(){cout << "默认构造" << endl;}A(int n) {cout << "调用有参构造" << endl;if (n > 0)p = new int(n);//p指向一块int类型的内存,值为nelse{p = NULL;cout << "数据不准确" << endl;}}void a(){if (p) {cout << "打印p指向堆区内存值:" << *p << endl;}
}
};
int main() {A t(1);//输出:调用有参构造。括号法相当于A t=A(1);A t1 = A(3);//输出:调用有参构造。显示法A t2 = 3;//输出:调用有参构造。隐式转换法,在此处会调用参数为int类型的构造函数,将3转换为A类型对象A t3();//不是括号发,编译器会把它认为是函数声明,A是返回值类型.t3是函数名,()是函数参数A t4;//输出:默认构造。调用无参构造return 0;
}
构造函数的调用规则
在默认情况下,C++至少会给一个类添加3个函数:
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数,对属性进行值拷贝。(简单的赋值)
构造函数调用规则:
1.如果用户定义有参构造,C++不再提供默认的无参构造,但会提供默认的拷贝构造
2.如果用户定义了拷贝构造,C++不再提供其他的任何构造函数(无参、有参、默认拷贝构造)
#include<iostream>
#include<vector>
using namespace std;
class Person {public:int n;Person() {cout << "无参构造" << endl;}Person(int n) {this->n = n;cout << " 有参构造" << endl;}Person(const Person& other) {this->n = other.n;cout << " 拷贝构造" << endl;}~Person() {cout << "析构函数" << endl;}
};
void test1() {Person p1(18);Person p2(p1);//如果不写拷贝构造,编译器会自动添加默认的拷贝构造(浅拷贝)//此处的拷贝构造,相当于使用一个已经创建完毕的对象(已经存在的对象)初始化一个新对象cout << "p2为:" << p2.n << endl;
}
void test2() {//如果用户提供有参构造,编译器不会提供默认的无参构造,但会提供默认的拷贝构造Person p1;//此时如果用户没有提供默认构造,编译器会报错Person p2(10);//调用用户提供的有参构造Person p3(p2);//调用拷贝构造,如果此时用户没有提供拷贝构造,编译器会提供默认的拷贝构造//如果用户提供了拷贝构造,编译器不会提供其他任何的拷贝构造Person p4;//此时如果用户没有提供默认构造,编译器会报错Person p5(10);//调用用户提供的有参构造,此时如果用户没有提供有参构造,编译器会报错Person p6(p5);//调用拷贝构造
}
int main() {test1();return 0;
}
二、对象的清理
对象需要调用析构函数来清理
析构函数
主要作用在于对象销毁前系统自动调用,执行一些清理工作
语法:~( )类名{ }
1.析构函数没有返回值,也不用写void
2.函数名跟类名相同,在名称前加符号:~
3.析构函数不可以有参数,因此不能发生重载
4.程序在对象销毁前会自动调用析构,无需手动调用,而且只会调用一次
#include<iostream>
using namespace std;
class Pointer {int* p=NULL;
public:Pointer() {cout << "默认构造" << endl;}Pointer(int n) {cout << "调用有参构造" << endl;if (n > 0) {p = new int[n];//使用构造函数在堆区申请了n个int类型的变量}}//析构函数用于帮助我们释放指针变量指向的堆区内存~Pointer() {if (p)delete[]p;}
};
void test() {Pointer p(2);
}
int main() {test();return 0;
}