【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.没有返回值也不需要写void
    2.函数名称与类名相同
    3.构造函数可以有参数,可发生重载
    4.程序调用对象的时候会自动调用构造,无需手动调用,且只调用一次
析构函数:
    1.没有返回值也不需要写void
    2.函数名固定为 ~类名
    3.析构函数不能有参数,也不能重载
    4.程序运行结束会自动调用析构释放内存,无需手动调用,且只执行一次

(一)构造函数分类

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 p1
    3.隐式法
        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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值