【C++学习】对象特性--构造函数
一、类的封装
访问权限:
公共权限public :类的内外都可以使用
私有权限private : 仅类内可以访问,继承后不可访问
保护权限protected :仅类内可以访问,继承后可以访问
#include <iostream> //标准输入输出控件
#include <iomanip>
#include <string> //使用string声明字符串时必须包含
#include <cstdlib> //汉化
using namespace std;// 构造与析构
class Person
{
private:string name;int age;public:// 有参构造函数Person(const string &name, int age){this->name = name;this->age = age;};// 析构函数~Person() {}; // 对象销毁时清理内存// 向外部提供访问内部属性的方法void getMess(){cout << "构造函数初始化:" << name << age << endl;};
protected:
};int main()
{system("chcp 65001 >nul"); // 汉化// using std::cout;Person p("zhangsan",25);//实例化一个叫张三,25岁的对象cout << p.name << p.age <<endl;return 0;
}
二、构造函数与析构函数
(一)构造函数分类
1.按参数分类 有参数 无参数
2.按类型分类 普通构造 拷贝构造函数拷贝构造函数:Person( const Person &p ){age = p.age;}
(二)构造函数的调用方法
1.括号法Person p;//无参构造,默认构造Person p1(10);//有参构造Person p2(p1);//拷贝构造2.显示法Person p = Person(10);Person(10);//匿名对象,执行完后系统会立即回收匿名对象Person p = Person(p1);//拷贝构造注意:不要用拷贝构造函数创建初始化一个匿名对象 Person (p1) === Person p13.隐式法Person p = 10; === Person p = Person(10);Person p = P1;//拷贝构造
(三)拷贝构造函数的场景
1.使用一个创建完毕的对象来初始化一个新对象
#include <iostream> //标准输入输出控件
#include <iomanip>
#include <string> //使用string声明字符串时必须包含
#include <cstdlib> //汉化
using namespace std;class Car
{
private:int carNumber;public:// 构造函数的重构// 默认构造函数,无参构造Car() { cout << "调用无参构造函数" << endl; };// 有参构造Car(int num){carNumber = num;cout << "调用有参构造函数" << endl;};// 拷贝构造Car(const Car &car){carNumber = car.carNumber;cout << "调用拷贝构造函数" << endl;};~Car() { cout << "调用析构函数" << endl; };int getCarNumber(){return carNumber;};protected:
};void test1()
{Car car1;Car car2(10);Car car3(car2);cout << "car2构造结果:" << car2.getCarNumber() << endl;cout << "car3构造结果:" << car3.getCarNumber() << endl;
};int main()
{system("chcp 65001 >nul"); // 汉化// using std::cout;/* 拷贝构造函数的使用场景*/test1(); // 使用一个创建完毕的对象来初始化一个新对象return 0;
}
2.值传递的方式给函数参数传参
#include <iostream> //标准输入输出控件
#include <iomanip>
#include <string> //使用string声明字符串时必须包含
#include <cstdlib> //汉化
using namespace std;class Car
{
private:int carNumber;public:// 构造函数的重构// 默认构造函数,无参构造Car() { cout << "调用无参构造函数" << endl; };// 有参构造Car(int num){carNumber = num;cout << "调用有参构造函数" << endl;};// 拷贝构造Car(const Car &car){carNumber = car.carNumber;cout << "调用拷贝构造函数" << endl;};~Car() { cout << "调用析构函数" << endl; };int getCarNumber(){return carNumber;};protected:
};void test2_1(Car c1) {};void test2()
{Car c1;test2_1(c1);
};int main()
{system("chcp 65001 >nul"); // 汉化// using std::cout;/* 拷贝构造函数的使用场景*/test2(); // 值传递的方式给函数参数传参return 0;
}
3.用值的方式返回一个局部对象
#include <iostream> //标准输入输出控件
#include <iomanip>
#include <string> //使用string声明字符串时必须包含
#include <cstdlib> //汉化
using namespace std;class Car
{
private:int carNumber;public:// 构造函数的重构// 默认构造函数,无参构造Car() { cout << "调用无参构造函数" << endl; };// 有参构造Car(int num){carNumber = num;cout << "调用有参构造函数" << endl;};// 拷贝构造Car(const Car &car){carNumber = car.carNumber;cout << "调用拷贝构造函数" << endl;};~Car() { cout << "调用析构函数" << endl; };int getCarNumber(){return carNumber;};protected:
};Car test3_1()
{Car c1;return c1;
};void test3()
{Car c1 = test3_1();/* 正常来说,这里会执行两次拷贝构造函数第一次是返回时,return c1 会先将 c1 拷贝到一个临时对象(调用拷贝函数)第二次是执行 Car c1 = 临时对象,会再将临时对象拷贝到 test3() 中的 c1(再调用一次拷贝构造函数)但编译器会优化这两步复制,直接在 test3() 的 c1 内存位置构造 test3_1() 中的对象在编译时关闭优化(如 GCC 用 -fno-elide-constructors 选项),就能看到拷贝构造函数被调用*/
};int main()
{system("chcp 65001 >nul"); // 汉化// using std::cout;/* 拷贝构造函数的使用场景*/test3(); // 用值的方式返回一个局部对象return 0;
}
(四)构造函数的调用规则
1.默认情况下编译器至少给一个类提供三个默认构造函数(无参构造,析构函数,拷贝构造)2.写了自定义的有参构造函数后,编译器不提供无参构造函数,但提供拷贝构造函数3.写了自定义构造函数后,编译器不再提供其他构造函数
三、易混淆知识点
(一)class 与 struct 的区别
class的默认访问权限是private
struct的默认访问权限是public
(二)拷贝构造函数的参数可以不用const吗
非 const 引用只能绑定到 “可修改的左值”(如普通变量),无法绑定到常量对象或临时对象
class Car {public:int id;// 拷贝构造函数:参数为非 const 引用Car(Car& other) {this->id = other.id;}};int main() {Car c1;Car c2 = c1; // 正确:c1 是可修改的左值,可绑定到非 const 引用const Car c3; // 常量对象Car c4 = c3; // 错误:无法用非 const 引用绑定常量对象Car c5 = Car(); // 错误:无法用非 const 引用绑定临时对象(Car() 是临时对象)return 0;}
