C++语言类中各个重要函数原理

目录

自定义命名空间

cpp 复制代码
// 命名空间

#include <iostream>

// 声明std,我们的main函数就可以直接使用里面的成员,不需要使用 std::
using namespace std; // C++自己的命名空间 (C# .net 命名空间)

// 自定义命名空间
namespace derry1 {
    int age = 33;
    char * name = "猛男1";

    void show() {
        cout << "name:" << name << ", age:" << age << endl;
    }

    void action() {
        cout << "derry1 action" << endl;
    }
}

// TODO ------ 命名空间里面重复的函数
// 自定义命名空间
namespace derry2 {
    void action() {
        cout << "derry2 action" << endl;
    }
}

// TODO ------ 小概率会遇到的情况,命名空间的嵌套
// 自定义命名空间
namespace derry3 {
    namespace derry3Inner {
        namespace derry3Inner1 {
            namespace derry3Inner2 {
                namespace derry3Inner3 {
                    void out() {
                        cout << "爱恨情仇人消瘦,悲欢起落人寂寞" << endl;
                    }
                }
            }
        }
    }
}

// 声明各个写的 命名空间
// using namespace derry1;

int main() {
    cout << "命名空间" << endl;

    // 声明各个写的 命名空间
    using namespace derry1;

    int ageValue = derry1::age; // 方式1 使用 刚刚声明的命名空间
    derry1::show(); // 使用 刚刚声明的命名空间

    ageValue = age; // 方式2 直接去引出来 ::
    show(); // 直接去引出来 ::


    // TODO ------ 命名空间里面重复的函数
    using namespace derry2;
    // action(); 很尴尬
    derry1::action();
    derry2::action();

    // TODO ------ 小概率会遇到的情况,命名空间的嵌套

    // 第一种方式 先声明命名空间  再使用
    using namespace derry3::derry3Inner::derry3Inner1::derry3Inner2::derry3Inner3;
    // 再使用
    out();

    // 第二种方式 直接使用
    derry3::derry3Inner::derry3Inner1::derry3Inner2::derry3Inner3::out();

    return 0;
}
bash 复制代码
命名空间
name:猛男1, age:33
name:猛男1, age:33
derry1 action
derry2 action
爱恨情仇人消瘦,悲欢起落人寂寞
爱恨情仇人消瘦,悲欢起落人寂寞

构造函数详讲

cpp 复制代码
// 1.构造函数详讲, 2.析构函数,  3.Java/KT的所谓的析构函数。
#include <iostream>
#include <string.h>
using namespace std;

class Student {

// 构造函数
public:
    // 空参数构造函数
    Student() {
        cout << "空参数构造函数" << endl;
    }

    // 一个参数的构造函数
    // :Student(name, 87) 等价 1.调用两个参数的构造函数, 2.再调用当前函数
    // 学生说的:先调用两个参数的,再调用一个的
    Student(char *name) :Student(name, 87) {
        cout << "一个参数的构造函数" << endl;
        this->name = name;
    }
    // 系统源码中是写的
    // :name(name) 等价 this->name = name;
    /*Student(char * name) :name(name) {
        cout << "一个参数的构造函数" << endl;
    }*/

    // 两个参数的构造函数
    Student(char *name, int age) {
        // this->name = name;

        // 堆区
        this->name = (char *) (malloc(sizeof(char *) * 10));
        strcpy(this->name, name);

        this->age = age;
        cout << "两个参数的构造函数" << endl;
    }

    // 析构函数 Student对象的,临终遗言,Student对象被回收了,你做一些释放工作
    // delete stu 的时候,我们的析构函数一定执行
    // free不会执行析构函数,也意味着,你没法在析构函数里面,做释放工作, malloc也不会调用构造函数
    ~Student() {
        cout << "析构函数" << endl;

        // 必须释放 堆区开辟的成员
        if (this->name) {
            free(this->name);
            this->name = NULL; // 执行NULL的地址,避免出现悬空指针
        }
    }

// 私有属性
private:
    char *name;
    int age;

// 公开的 set get 函数
public:
    int getAge() {
        return this->age;
    }

    char *getName() {
        return this->name;
    }

    void setAge(int age) {
        this->age = age;
    }

    void setName(char *name) {
        this->name = name;
    }
};

int main() {
    // TODO  =========== 下面是栈区 开辟空间的

    /*Student stu; // 调用 空参数构造函数
    stu.setAge(34);
    stu.setName("李元霸");
    cout << "name:" << stu.getName() << ", age:" << stu.getAge() <<  endl;*/

    // Student stu("雄霸", 30);
    /*Student stu("李连杰");
    cout << "name:" << stu.getName() << ", age:" << stu.getAge() <<  endl;*/

    // TODO =========== 下面是堆区 开辟空间的  堆区必须手动释放,否则内存占用越来

    // 系统源码中,会看到,很多使用 new 关键字

    // *stu  ->:调用一级指针的成员
    // new/delete
    // C++中,必须使用 new/delete 一套
    Student *stu = new Student("杜子腾", 26);
    cout << "name:" << stu->getName() << ", age:" << stu->getAge() <<  endl;
    delete stu;

    // free(stu); 这样写是不规范的,不按人家规则来

    // 还有人这样写 (C工程师,搞了六年,改不了自己的习惯, malloc)
    // malloc 你的构造函数都没有调用,这个不行的
    /*Student *stu2 = (Student*) malloc(sizeof(Student));
    free(stu2);*/

    // 纠结:C++有析构函数(临终遗言 释放工作)    Java KT 临终遗言 是什么?

    return 0;
}

纠结new/delete。

new/delete 是一套 会调用构造函数 与 析构函数 【C++标准规范】

malloc/free是一套 不调用构造函数 与 析构函数 【C的范畴,虽然不推荐,但是也是可以的】

而在java和kotlin中的回收

java 复制代码
package test;

import java.io.Closeable;
import java.io.IOException;

// 隐士 extends Object
public class JavaHelp implements Closeable {


    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        close();
    }

    @Override
    public void close() throws IOException {

    }
}
java 复制代码
package test;

// 默认隐士  extends Object
public class Stu {

    // 并不是这样说的,Java调用了finalize函数,代表这个类可能被回收了(回收的前兆)
    // 此类加入到queue队列中,等待虚拟机来处理(只有虚拟机处理回收了,才叫回收)
    @Override
    protected void finalize() throws Throwable {
        super.finalize();

        System.out.println("Java 我被回收了");
    }
}
kotlin 复制代码
package test


// 隐士的 : Any?
// KT做不大,但是可以借助Java来做
class Student : JavaHelp() {

    override fun close() {
        super.close()

        println("KT 我被回收了");
    }


}
java 复制代码
package test;

public class Main {

    public static void main(String[] aaa) {

        // ====== Java 回收

        Stu stu = new Stu();

        stu = null;
        System.gc();; // gc机制来扫描吧,gc一过来发现,stu还有指向,扫你妹啊


        // ===== KT 回收

        Student student = new Student();
        student = null;
        System.gc();;
    }

}

拷贝构造函数

cpp 复制代码
// 4.拷贝构造函数。

#include <iostream>
#include <string.h>

using namespace std;

class Student {

public:
    Student() { cout << "空参数构造函数" << endl; }

    // 两个参数的构造函数
    Student(char *name, int age) : name(name), age(age) {
        cout << "两个参数构造函数" << endl;
    }

    // 析构函数
    // ~Student(char * name) { } 这样写,就不是析构函数了,如果你这样写,C/C++编译器对你很无语
    ~Student() {
        cout << "析构函数" << endl;
    }

    // 以前是默认有一个拷贝构造函数,stu2 = stu1 默认赋值 【隐士 你看不到】

    // 拷贝构造函数,它默认有,我们看不到,一旦我们写拷贝构造函数,会覆盖她
    // 对象1 = 对象2
    // 覆盖拷贝构造函数
    Student(const Student & student) { // 常量引用:只读的,不让你修改
        cout << "拷贝构造函数" << endl;

        // 我们自己赋值
        // 为什么要自己赋值,自己来控制,就可以 例如:-10
        this->name = student.name;
        this->age = student.age - 10;

        cout << "自定义拷贝构造函数 内存地址 " << &student << endl;
    }

// 私有属性
private:
    char *name;
    int age;

// 公开的 set get 函数
public:
    int getAge() {
        return this->age;
    }

    char *getName() {
        return this->name;
    }

    void setAge(int age) {
        this->age = age;
    }

    void setName(char *name) {
        this->name = name;
    }
};

struct Person {
    int age;
    char *name;
};

// TODO = 号的意义 隐士代码,引出 拷贝构造函数
/*
int main() {
    Person person1 = {100, "张三丰"};

    // = 你看起来,没有什么特殊,隐士的代码:你看不到  C/C++编译器 会把p1的成员值赋值给p2成员
    Person person2 = person1;

    cout << &person1 << endl;
    cout << &person2 << endl;

    cout << person2.name << ",  " << person2.age << endl;

    // 思考:对象 对象1=对象2  默认的 拷贝构造函数

    return 0;
}*/

// TODO  拷贝构造函数
/*
int main() {
    Student stu1("李鬼", 34);
    Student stu2 = stu1;

    cout << stu2.getName() << " , " <<  stu2.getAge() <<  endl;
    cout << "main " << &stu1 << endl; // 地址的打印是一样的,  注意:cnetos的环境 地址打印有差异,要注意



    // TODO  拷贝构造函数的注意点:
    // Student stu1("李鬼", 34);

    // Student stu2;
    // stu2 = stu1; // 这样赋值是不会调用 自定义拷贝构造函数,但是会调用默认赋值
    // Student stu2 = stu1;  // 这样赋值是会调用 自定义拷贝构造函数,我们自己赋值

    // cout << stu2.getName() << " , " <<  stu2.getAge() <<  endl;

    getchar(); // 程序等待在这一行

    return 0;
} // main函数弹,stu1栈成员会回收  stu2栈成员会回收
*/

// TODO 这种写法 拷贝构造函数  到底会不会调用
int main() {
    Student *student1 = new Student("杜子腾", 39);

    Student *student2 = student1;  // 压根就不会执行拷贝构造函数(指针指向问题,和我们刚刚那个  对象2=对象1 是两回事)

    // 原理,为什么不会? 纠结

    student2->setAge(99);

    cout << student1->getName() << student1->getAge() << endl;

    // "->"调用一级指针的成员    和    "."非指针的操作  有啥区别

    return 0;
}

// Clion和VS差异太大了,放到下一节课,包括 内存地址的分析,等等,到下节课讲
// 下节课讲: 拷贝构造函数的,深拷贝 和 浅拷贝

指针常量 常量指针 常量指针常量

cpp 复制代码
// 指针常量 常量指针 常量指针常量

#include <iostream>
#include <string.h>
#include <string.h>

using namespace std;

int main() {

    // *strcpy (char *__restrict, const char *__restrict);
    // strcpy()


    int number = 9;
    int number2 = 8;

    // 大道至简 一分钟搞定

    // 常量指针
    const int * numberP1 = &number;
    // *numberP1 = 100; // 报错,不允许去修改【常量指针】存放地址所对应的值
    // numberP1 = &number2; // OK,允许重新指向【常量指针】存放的地址

    //  指针常量
    int* const numberP2 = &number;
    *numberP2 = 100; // OK,允许去修改【指针常量】存放地址所对应的值
    // numberP2 = &number2; // 报错,不允许重新指向【指针常量】存放的地址

    // 常量指针常量
    const int * const numberP3 = &number;
    // *numberP3 = 100; // 报错,不允许去修改【常量指针常量】存放地址所对应的值
    // numberP3 = &number2; // 报错,不允许重新指向【常量指针常量】存放的地址

    return 0;
}
相关推荐
chilavert3181 小时前
技术演进中的开发沉思-370:final 关键字(上)
java·开发语言
一切顺势而行1 小时前
python 文件目录操作
java·前端·python
砚边数影2 小时前
智慧校园后端演进:如何处理每日亿级传感器数据的“存、压、查”?
java·数据库·时序数据库·kingbase·数据库平替用金仓·金仓数据库
stripe-python2 小时前
十二重铲雪法(下)
c++·算法
D_evil__2 小时前
【Effective Modern C++】第五章:右值引用、移动语义和完美转发:29. 认识移动操作的缺点
c++
遇见你的雩风2 小时前
【Golang】--- Channel
开发语言·golang
zlpzpl2 小时前
Java总结进阶之路 (基础二 )
java·开发语言·python
xyq20242 小时前
Chart.js 折线图深入解析与使用指南
开发语言
Evand J2 小时前
【UWB与IMU紧耦合定位,MATLAB例程】UWB的TOA定位方法,与IMU紧耦合,对目标轨迹定位并输出误差统计。适用于二维平面的高精度定位导航
开发语言·matlab·平面·uwb·组合导航