当前位置: 首页 > news >正文

C++类和对象入门(二)

目录

     目录

一、类的默认成员函数

二.构造函数

2.1函数名与类名相同

 2.2构造函数无返回值

2.3 对象实例化时系统会自动调用

2.4支持函数重载

2.5默认构造函数

2.6无参构造函数与全缺省构造函数与默认构造函数

三、析构函数

3.1析构函数名称

3.2无参数和返回值

3.3一个类只能有一个析构函数

3.4自动调用

3.5显式写析构函数

3.6可以不写的情况

3.7析构函数执行的顺序

四、拷贝构造函数

4.1定义

4.2本质

4.3第一个参数

4.4自定义类型对象的拷贝

4.5若没有显式地写,编译器会自动生成

4.6拷贝函数的传值返回

结语


        前言,本文所介绍的知识建立在上文:《C++类和对象入门》

        下面我们来继续介绍C++类和对象的进一步讲解和介绍。

一、类的默认成员函数

        在C++中存在默认成员函数,默认成员函数是指在用户没有显写函数的时候,编译器在C++中会自动生成的函数,一般会有六个函数默认生成,如下图,理解这些函数的行为和作用是理解C++类机制的基础。

        

        本文将详细介绍3个默认成员函数:构造函数、析构函数和拷贝函数。


二.构造函数

        构造函数是用于初始化对象的特殊成员函数,它的主要任务是初始化对象的域元变量,并不为对象分配内存,确保对象在创建的时候是有效的。

2.1函数名与类名相同

        C++语法要求,构造函数的名称要和类名相同,这能让编译器识别这个是构造函数而不是普通成员函数。

class MyClass {
public:
    MyClass() { /* 构造函数体 */ }
};

 2.2构造函数无返回值

         构造函数无返回值,甚至不需要void。它的作用仅仅是去初始化对象,不需要任何返回值。

class MyClass {
public:
    MyClass() { /* 构造函数体 */ }
};

2.3 对象实例化时系统会自动调用

        构造函数在对象实例化时自动调用。开发者不需要显式调用构造函数,编译器会在对象创建时自动执行它。

2.4支持函数重载

        构造函数支持函数重载,不同的函数可以使用同一个函数名称,但是需要保证函数参数列表是不同的,例如:

class MyClass {
public:
    MyClass() { /* 无参构造函数 */ }
    MyClass(int x) { /* 带参构造函数 */ }
};

2.5默认构造函数

        默认构造函数提供了一个基本的初始化方式。如果用户定义了其他形式的构造函数(如带参数的),编译器认为用户不再需要默认构造函数,因此不会自动生成。

2.6无参构造函数与全缺省构造函数与默认构造函数

        首先声明,这三种函数不能同时存在,三种函数作用相似,初始化对象不需要提供显式参数的函数,但这三个函数任意其一可以和带参数的函数一起存在(函数重载)。

        例子:

#include <iostream>
using namespace std;

class MyClass {
public:
    // 全缺省构造函数
    MyClass(int x = 10, int y = 20) {
        //函数体
    }

    // 普通带参构造函数
    MyClass(double z) {
        //函数体
    }
};

int main() {
    MyClass obj1;         
    MyClass obj2(10);     
    MyClass obj3(3.14); 
    return 0;
}

三、析构函数

        析构函数和构造函数的作用相反,它用于在函数的生命周期结束的时候释放资源。

值得说的是,析构函数会在对象销毁时自动调用,以完成对象中资源的清理工作。这一特性使得C++能够有效地管理内存和其他资源,防止资源泄漏。

3.1析构函数名称

        析构函数名和类名相同,在前面加上一个 ~

class MyClass {
public:
    ~MyClass() {
        // 析构函数体
    }
};

3.2无参数和返回值

        析构函数是用来清理对象的资源的,不需要参数和返回值。

class MyClass {
public:
    ~MyClass() {
        // 无参数,无返回值
    }
};

3.3一个类只能有一个析构函数

        C++规定,一个类只能有一个析构函数,因为一个对象只能在生命周期结束时被销毁一次。

class MyClass {
public:
    ~MyClass() {
        // 只能有一个析构函数
    }
};

3.4自动调用

        当一个对象的生命周期结束(如对象超出作用域或显式删除对象)时,系统会自动调用析构函数来清理资源。

        如果显式定义了析构函数,对于自定义类型的成员变量,它们的析构函数也会被自动调用。

class MyClass {
private:
    std::string _name; // 自定义类型成员
public:
    ~MyClass() {
        // 自定义类型的成员变量会自动调用其析构函数
    }
};

3.5显式写析构函数

        如果显式定义了析构函数,C++会确保自定义类型的成员变量,在生命周期结束的时候,也会自动调用他的析构函数。

class MYclass
{
private:
    std::string_name;
public:
    ~MYclass()
{}
}

3.6可以不写的情况

        如果类里没有需要动态分配的资源或者需要手动释放的资源,可以不需要写析构函数,可以使用编译器的默认析构函数。例如:

class Myclass
{
private:
    int_value;//没有需要动态分配的资源
}

3.7析构函数执行的顺序

        C++规定,先定义的函数后析构。

这一规则保证了对象按照先进后出的顺序进行销毁,这符合栈的逻辑。

class Myclass
{
public:
    ~Myclass()
    {}
};
int main()
{
Myclass odj 1;
Myclass obj 2;//这里2回比1先销毁
return 0;
}

        下面,将用两个具体的代码实例帮助大家理解构造函数和析构函数在C++中的性质和作用。

实例一:利用两个栈实现队列

#include<iostream>
using namespace std;

typedef int STDataType;

class Stack {
public:
    Stack(int n = 4) {
        _a = (STDataType*)malloc(sizeof(STDataType) * n);
        if (_a == nullptr) {
            perror("malloc申请空间失败");
            return;
        }
        _capacity = n;
        _top = 0;
    }

    ~Stack() { // 自定义析构函数,释放动态分配的内存
        cout << "~Stack()" << endl;
        free(_a);
        _a = nullptr;
        _top = _capacity = 0;
    }

private:
    STDataType* _a;
    size_t _capacity;
    size_t _top;
};

// 两个Stack实现队列
class MyQueue {
public:
    MyQueue() : pushst(), popst() {}

    // 默认析构函数自动调用两个Stack成员的析构函数
    // 显式定义的析构函数,也会自动调用Stack成员的析构函数
    /*~MyQueue() {}*/

private:
    Stack pushst;
    Stack popst;
};

int main() {
    Stack st;

    MyQueue mq; // MyQueue的析构函数会自动调用pushst和popst的析构函数

    return 0;
}

实例二:用C++解决括号匹配

#include<iostream>
using namespace std;

bool isValid(const char* s) {
    Stack st;

    while (*s) {
        if (*s == '[' || *s == '(' || *s == '{') {
            st.Push(*s);
        } else {
            if (st.Empty()) {
                return false;
            }

            char top = st.Top();
            st.Pop();

            if ((*s == ']' && top != '[') ||
                (*s == '}' && top != '{') ||
                (*s == ')' && top != '(')) {
                return false;
            }
        }
        ++s;
    }

    return st.Empty(); // 确保所有括号都匹配
}

int main() {
    cout << isValid("[()][]") << endl; // 输出1(true)
    cout << isValid("[(])[]") << endl; // 输出0(false)

    return 0;
}

四、拷贝构造函数

4.1定义

        拷贝构造是一种构造函数,用于通过一个已经存在的对象来构造一个新的对象。

        在C++中,如果一个函数的第一个参数是自身类型的引用,那么这个函数就是拷贝构造函数。

4.2本质

        拷贝构造函数本质就是原函数的一个函数重载

        因为定义中讲,如果一个函数的第一个参数是自身类型的引用,那么这个函数就是拷贝构造函数。那么这两个函数的函数名必然相同,只不过参数列表不同,一个是函数本身的参数列表,另一个是同类对象的引用。

4.3第一个参数

        注意!!拷贝构造函数的第一个参数必须调用类类型对象的引用,不能传值,否则就会出现无限调用拷贝构造,导致编译错误。如下图:

4.4自定义类型对象的拷贝

        在C++中,无论是传值,还是从函数内部返回一个对象,C++都调用了拷贝函数来创建新的对象。

4.5若没有显式地写,编译器会自动生成

        如果没有显式的写拷贝函数,编译器会自动生成一个拷贝函数,对函数的内置类型进行拷贝,不过注意,这是浅拷贝,浅拷贝指的是例如简单变量,数组等,可以直接拷贝一份给别的地方用,但是如果遇到例如,栈,这一类需要动态分配资源的,浅拷贝会导致例如两个资源共用一个空间的矛盾产生,这时需要自定义函数来实现深拷贝。

4.6拷贝函数的传值返回

        在C++中,通过值返回对象时,编译器会调用拷贝构造函数来创建返回值的副本。如果通过引用返回对象,则没有拷贝发生。然而,引用返回需要确保返回的对象在函数结束后仍然存在,否则会导致悬空引用。例如:

MyClass ReturnByValue() {
    MyClass temp(10);
    return temp;  // 调用拷贝构造函数,返回对象副本
}

MyClass& ReturnByReference() {
    static MyClass temp(10);  // 使用static,确保返回的引用有效
    return temp;  // 返回引用,不调用拷贝构造函数
}

int main() {
    MyClass obj1 = ReturnByValue();    // 调用拷贝构造函数
    MyClass& obj2 = ReturnByReference();  // 不调用拷贝构造函数
    return 0;
}


结语

至此,本文介绍的关于C++入门的部分知识正式结束,日后我会更新更多关于C++的基础入门知识,如果本文能帮助到阅读文章的你,就请点赞转发收藏吧,您的支持也是我继续学习和更新的动力,感谢支持!!

相关文章:

  • 支持IPD项目管理的9大系统,哪款工具能有效提高项目控制能力
  • 15. LangChain实战项目2——易速鲜花海报文案生成
  • 关于大型语言模型的结构修剪
  • WSBDF レクチア 定义2 引理3 wsbdf的乘子
  • 两路导播台mov素材硬盘格式化后的恢复方法
  • 【C++/数据结构】队列
  • java2025springboot面试题第一弹
  • WhiteNoise的用法
  • flutter 网络请求封装与json序列化与反序列化
  • FPGA开发,使用Deepseek V3还是R1(5):temperature设置
  • C++(四)类与对象 下
  • 特辣的海藻!7
  • 深入浅出理解编译器:前端视角
  • 477. 汉明距离总和
  • 基于RKNN的嵌入式深度学习开发(2)
  • 计算机网络---TCP三握四挥
  • 基于Ollama安装deepseek-r1模型搭建本地知识库(Dify、MaxKb、Open-WebUi、AnythingLLM、RAGFlow、FastGPT)
  • 钉钉小程序(企业内部应用)开发--钉钉小程序web-view嵌套H5与小程序之间的通信(H5跳转钉钉小程序小程序postMessage)
  • 计算机毕业设计SpringBoot+Vue.js保险合同管理系统(源码+文档+PPT+讲解)
  • 相机引导2_两个固定相机引导机器人把芯片装入外壳
  • 做的网站需要什么技术支持/经典软文案例分析
  • 导航网站移动端流量占比/宁波网站关键词优化代码
  • 外贸 网站 建设 高端/网站代运营推广
  • 找柳市做网站/网络优化公司
  • 怎么做离线网站/今日最新重大新闻
  • 佛山商业网站建设/培训网络营销的机构