C++基础三(构造函数,形参默认值,函数重载,单例模式,析构函数,内联函数,拷贝构造函数)

news2024/11/23 21:31:14

    C++有六个默认函数,分别是:   

 1、默认构造函数;   

 2、默认拷贝构造函数;     

3、默认析构函数;   

 4、赋值运算符;   

 5、取址运算符;     

6、取址运算符const;

构造函数

构造函数(初始化类成员变量):
    1、属于类的成员函数之一
    2、构造函数没有返回类型
    3、构造函数的函数名必须与类名相同
    4、构造函数不允许手动调用(不能通过类对象调用)
    5、构造函数在类对象创建时会被自动调用
    6、如果没有显示声明构造函数,系统会生成一个默认的构造函数
    7、如果显示声明了构造函数,那么默认构造函数将不会在被创建
    8、构造函数不被设置为静态成员函数
    9、构造函数的函数首部之前或函数首部之后不能用const修饰
    10、new一个类指针也会触发构造函数的调用, malloc不会
    11、构造函数通过函数重载的方式也可以拥有多个
    12、构造函数也可以使用形参默认值
    13、构造函数可以是private的

#include <string.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

#if 0 // 构造函数

class Node
{
    public:
        //Node();
        Node(int n = 0, char* ptr = NULL, float score = 1.3f);
        // static Node(); // error
        // Node() const;  // error
        // const Node();  // error

    private:
        int m_num;
        char* m_ptr;
        float m_fscore;
};


// 类成员变量初始化方式2(常用这种方式)
// 通常普通类成员变量都需要在构造函数上进行初始化。
//Node::Node() 
//    : m_num(111),
//      m_ptr(NULL),
//      m_fscore(0.0) 
//{
//    // 类成员变量初始化方式1:
//    //m_num = 10;
//
//    cout << "construct: " << m_num << endl;
//}

Node::Node(int n, char* ptr, float score)
    : m_num(n),
      m_ptr(NULL),
      m_fscore(score)
{
    m_ptr = new char[100];

    strcpy(m_ptr, ptr);

    cout << m_num << " : " << m_ptr << " : " << m_fscore << endl;
}

int main(int argc,char *argv[])
{
    // 触发构造函数调用
    Node n;
    // n.Node(); // error


    Node n1(1, "st", 1.1);

    // 触发构造函数调用
    //Node* n1 = new Node;

    // 不会触发构造函数调用
    //Node* n2 = (Node*)malloc(sizeof(Node));

    return 0;
}
#endif


形参默认值

形参默认值:
    1、给函数的形参一个默认的值。
    2、如果我们在调用函数时指定实参的值,则形参的默认值不生效。
    3、如果调用函数时没有给实参值,形参默认值才会生效。
    4、形参默认值只需要在函数声明时写出来即可。
       如果有函数声明的前提下, 在函数定义时写形参默认值会报错。
    5、形参默认值只能出现在形参列表的最右边(后边)。

#if 0 // 形参默认值

class Node
{
    public:
        // 形参默认值
        void fun(int x, int y, int num = 12, int z = 1);
        void display();

    private:
        int m_num;
};

void Node::fun(int x, int y, int num, int z)
{
    m_num = num;
}

void Node::display()
{
    cout << m_num << endl;
}

int main()
{
    Node n;
    n.fun(1, 2, 12345);
    n.display();

    n.fun(1, 2);
    n.display();

    return 0;
}

#endif

函数重载

函数重载:
    1、在C++允许出现同名函数
      (1) 形参个数不同
      (2) 形参类型不同
      (3) 形参顺序不同: 前提类型不同
      (4) 函数的返回类型不影响
    2、函数重载时,调用函数是在编译期间就确定了具体调用对象,
       因为我们将函数重载称之为静态联编
    3、重载函数调用时,不要出现二义性问题

#if 0 // 函数重载
#include <stdio.h>

void fun(int x, float y)
{
    cout << "fun(int x, float y)" << endl;
}

void fun(int x, int y)
{
    cout << "void fun(int x, int y)" << endl;
}

void fun(int x, int y, int z = 0)
{
    cout << "void fun(int x, int y, int z = 0)" << endl;
}

void fun()
{
    cout << "fun()" << endl;
}

void fun(float x, int y)
{
    cout << "fun(float x, int y)" << endl;
}

int main()
{   
    fun(1.1f, 12);
    fun(12, 1.3f);

    fun(1, 2, 3);
    fun(1, 2); // error: 出现了二义性

    return 0;
}

#endif

单例模式

#if 1 // 设计模式:单例模式

class Node
{
    public:
        static Node* getInstance();

    private:
        Node();

    private:
        static Node* m_ptr;
};

Node* Node::m_ptr = NULL;

Node::Node()
{
    cout << "construst" << endl;
}

Node* Node::getInstance()
{
    if (m_ptr == NULL)
    {
        m_ptr = new Node;
    }

    return m_ptr;
}

int main()
{
    //Node n; // error: ‘Node::Node()’ is private
    //Node* n1 = new Node; // error: ‘Node::Node()’ is private
    //Node* n2 = (Node*)malloc(sizeof(Node)); // 可以

    Node* n = Node::getInstance();
    cout << n << endl; 

    Node* n1 = Node::getInstance();
    cout << n1 << endl; 

    Node* n2 = Node::getInstance();
    cout << n2 << endl; 

    Node* n3 = Node::getInstance();
    cout << n3 << endl; 

    Node* n4 = Node::getInstance();
    cout << n4 << endl; 
    return 0;
}

析构函数

析构函数:
    1、类对象或类指针销毁时析构函数会被自动调用
    2、如果没有显示声明析构函数,则系统会生成一个默认的析构函数
    3、如果显示声明了析构函数,则不会在生成默认的析构函数
    4、析构函数没有返回类型,没有形参列表,且函数名与类名相同
    5、析构函数只有一个,不能重载
    6、析构函数不能设置为私有的
    7、析构函数可以手动调用,但不允许
    8、如果类对象的作用域相同,那么在销毁时析构函数的执行顺序与构造相反。

#include <iostream>
using namespace std;

class Node
{
    public:
        Node();
        Node(int n);
        ~Node();
        //~Node(int num = 0); // error: destructors may not have parameters
   
        void fun();
        inline void fun1()
        {
            cout << "fun1" << endl;
        }

    private:
        int* m_ptr;
};

Node::Node()
    : m_ptr(NULL)
{
    if (m_ptr == NULL)
    {
        m_ptr = new int[100];
    }

    cout << "construct" << endl;
}

Node::Node(int n)
    : m_ptr(NULL)
{
    if (m_ptr == NULL)
    {
        m_ptr = new int[100];
    }

    *m_ptr = n;

    cout << *m_ptr << "construct"  << endl;
}

void Node::fun()
{
    Node n(8);
    cout << "fun" << endl;
}

Node::~Node()
{
    cout << *m_ptr << "destruct" << endl;

    if (m_ptr != NULL)
    {
        delete[] m_ptr;
        m_ptr = NULL;
    }
}

int main(int argc,char *argv[])
{
    Node n0(0), n2(2);

    n0.fun();
    
    Node n3(3), n4(4), n5(5);
    //Node* n1 = new Node;
    //delete n1;

    // n0.~Node(); // 可以但不允许

    cout << "aaa" << endl;

    return 0;
}

内联函数

内联函数:
    1、在普通类成员函数声明之前添加 inline 关键字
    2、内联函数通常函数定义和函数声明都写在类声明中
    3、内联函数的函数体中不能出现复杂结构
    4、函数函数体中的代码一般3行左右
    5、通常被频繁调用的函数才需要设置为内联函数
    6、内联函数是进行函数逻辑的替换,其不进行真正的函数调用,减少系统开销
    7、系统会自动判断当前函数是否是内联函数,也会自动判别是否需要使用内联。

内联函数与c的宏函数有什么不同

1、宏函数是在编译阶段处理,是纯字符串替换; 内联函数是运行阶段处理,是函数逻辑替换; 2、宏函数无法调试;  内 联函数可以调试;

3、宏函数没有返回值;   内联函数有返回值;

4、宏函数不能访问类成员; 内联函数可以访问类成员;

拷贝构造函数

拷贝构造函数:
    1、拷贝构造函数属于构造函数的重载
    2、拷贝构造函数,要求形参中有一个当前类的类对象的引用
    3、如果没有显示声明拷贝构造函数,系统会生成一个默认的拷贝构造函数
    4、如果显示声明了拷贝构造函数,那么默认拷贝构造函数将不会在被创建
    5、当使用一个老对象去构造一个新对象时会调用拷贝构造函数
        (1) 用一个老对象构造一个新对象,或者新对象赋给老对象。
        (2) 当函数的形参是一个非引用的类对象时,实参到形参传递时。
        (3) 函数返回一个非引用的类对象时。
    6、如果没有显示声明和定义拷贝构造函数时,类中的非指针类成员的值是可以被拷贝的。
       默认拷贝构造函数负责执行了值的拷贝。
    7、如果显示声明和定义拷贝构造函数后,类中的所有成员变量都需要我们手动进行拷贝。
    8、拷贝分为浅拷贝和深拷贝,默认拷贝构造函数只能进行浅拷贝。
    9、浅拷贝只进行值的拷贝,深拷贝还会执行内存拷贝。

#include <iostream>
using namespace std;


class Node
{
    public:
        Node();
        Node(const Node& n);
        ~Node();

    private:
        int m_num;
        int* m_ptr;
};

Node::Node()
    : m_num(12),
      m_ptr(NULL)
{
    if (m_ptr == NULL)
    {
        m_ptr = new int[100];
    }

    *m_ptr = 123;

    cout << "construct" << m_num << " -- " << *m_ptr << endl;
}

Node::Node(const Node& n)
    : m_num(0)
{
    if (m_ptr == NULL)
    {
        m_ptr = new int[100];
    }

    *m_ptr = *(n.m_ptr);

    cout << "copy construct" << m_num << " -- " << *m_ptr << endl;
}

Node::~Node()
{
    cout << "destruct: " << m_num << " -- " << *m_ptr << " : " << m_ptr << endl;

    if (m_ptr != NULL)
    {
        delete[] m_ptr;
        m_ptr = NULL;
    }
}

int main(int argc,char *argv[])
{
    Node n1;
    Node n2(n1);

    return 0;
}


#include <iostream>
using namespace std;


class Node
{
    public:
        Node();
        Node(const Node& n);
        ~Node();

        Node fun(Node n);

    private:
        int m_num;
};

Node::Node()
    : m_num(12)
{
    cout << "construct: " << m_num << endl;
}

Node::Node(const Node& n)
    : m_num(0)
{
    cout << "copy construct: " << m_num << endl;
}

Node Node::fun(Node n)
{
    n.m_num = 111;
    cout << "fun" << endl;

    return n;
}

Node::~Node()
{
    cout << "destruct: " << m_num << endl;
}

int main(int argc,char *argv[])
{
    Node n1;
    //Node n2(n1);
    //Node n3 = n1;
    
    //Node n3 = n1.fun(n1);
    
    // 如果有返回,但我们没有接收的时候,系统会自动生成一个临时(隐藏)对象
    // 当前的临时(隐藏)对象的生存周期是从return开始,当前函数调用语句执行完毕结束。
    n1.fun(n1);

    cout << "---------" << endl;

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2229991.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言学习笔记】

C语言发展史&#xff1a; 1960 原型A语言->ALGOL语言 1963 CPL语言1967 BCPL1970 B语言1973 C语言 C语言特点&#xff1a; 基础性语言语法简洁 紧凑 方便 灵活(得益于指针)运算符 数据结构丰富结构化 模块化编程移植性好 执行效率…

智慧城市的守护者——智能井盖监测终端

城市化进程的加速推进使得基础设施建设成为提升城市品质的关键环节。然而&#xff0c;在这一进程中&#xff0c;市政公用设施中的井盖与地下线缆的安全问题却日益凸显。由于缺乏有效的实时监控与管理体系&#xff0c;给犯罪分子留下了可趁之机&#xff0c;频繁发生的井盖被盗及…

C语言 | Leetcode C语言题解之第513题找树左下角的值

题目&#xff1a; 题解&#xff1a; #define MAX_NODE_SIZE 10000int findBottomLeftValue(struct TreeNode* root){int ret;struct TreeNode** queue (struct TreeNode **)malloc(sizeof(struct TreeNode) * MAX_NODE_SIZE);int head 0;int tail 0;queue[tail] root;whil…

HarmonyOS应用开发者基础认证——初级闯关习题参考答案大全

相关文章 HarmonyOS应用开发者中级认证——中级闯关习题参考答案大全 HarmonyOS应用开发者高级认证——高级闯关习题参考答案大全 文章目录 HarmonyOS第一课 HarmonyOS介绍判断题单选题多选题 HarmonyOS第一课 DevEco Studio的使用判断题单选题多选题 HarmonyOS第一课 ArkTS语法…

SpringBoot 集成 Mybatis-Plus,LambdaQueryWrapper 使用方法

&#x1f3dd;️ 博主介绍 大家好&#xff0c;我是 一个搬砖的农民工&#xff0c;很高兴认识大家 &#x1f60a; ~ &#x1f468;‍&#x1f393; 个人介绍&#xff1a;本人是一名后端Java开发工程师&#xff0c;坐标北京 ~ &#x1f389; 感谢关注 &#x1f4d6; 一起学习 &am…

Word文档丢失抢救方法:15 个 Word 文档恢复工具

MS Word 文档恢复的重要性 对于严重依赖 Microsoft Word 创建和编辑文档的个人和企业来说&#xff0c;MS Word 文档恢复是一个至关重要的方面。 文件损坏、系统崩溃和其他意外事件可能会导致 Word 文档中存储的重要数据丢失。 及时恢复这些文档有助于节省时间、精力和资源。 本…

python实战项目51:selenium结合requests获取某众点评评论

python实战项目51:selenium结合requests获取某众点评评论 一、selenium获取cookies二、利用requests发送请求三、注意事项四、完整代码一、selenium获取cookies 首先,初始化selenium的webdriver,然后使用webdriver打开某众点评主页,之后手动扫码登录,利用selenium的get_c…

ETLCloud怎么样?深度解析其在数据管理中的表现

在BI或数据大屏等数据分析工具中&#xff0c;经常需要从多个业务系统中提取原始数据&#xff0c;然后对数据进行清洗、处理&#xff0c;以获取高质量、有效且干净的数据以供后续的BI进行数据统计和分析使用&#xff0c;从高质量的实现企业数据的价值变现。 然而&#xff0c;在…

《花少6》豆瓣评分3.9,“锅”不该周雨彤一个人背

《花儿与少年 第六季》以豆瓣评分3.9成为了整个系列IP有史以来口碑最差的一季节目。 播出过半的《花少6》终于在万众期待下开分了&#xff0c;豆瓣首次开分为4.8&#xff0c;实际上已经是“花少”史上最低评分&#xff0c;紧接着短短几天持续下滑至3.9分&#xff0c;让原本就不…

WPF+MVVM案例实战(十七)- 自定义字体图标按钮的封装与实现(上)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、案例效果1、按钮分类2、BC类按钮实现1、文件创建2、字体图标资源3、自定义依赖属性4、按钮特效样式实现3、案例实现1、案例效果 1、按钮分类 在WPF开发中,最常见的就是按钮的使用,这里我们总…

day-77 超级饮料的最大强化能量

思路 动态规划&#xff1a;因为每一步要么选A&#xff0c;要么选B&#xff0c;所以问题可以转换为求最后一步从A选或从B选中的较大值 解题过程 定义而二维数组dp,dp[i][0]表示最后一步从A取能获得的最大能量&#xff0c;dp[i][1]表示最后一步从B取能获得的最大能量状态转换方程…

91.【C语言】数据结构之单向链表的头删和尾删

目录 1.尾删函数SLTPopBack 代码示例(写入SList.c) 在SList.h中写入该函数的声明 main.c部分代码改为 ​编辑 分析 解决方法 方法1:双指针算法(快指针tail,慢指针pretail) 方法2 2.头删函数SLTPopFront 一个节点示意图 多个节点示意图 代码示例(写入SList.c) 在S…

C语言内幕--全局变量(结合内存分区、汇编视角看类型、连接器)

前言 学习资源&#xff1a;b站up主&#xff1a;底层技术栈学过C语言都知道&#xff0c;全局变量可以再全局中使用&#xff0c;其实全局变量内部还是涉及到不少知识&#xff0c;这里从内存分区、汇编视角看类型、连接器等角度看待全局变量&#xff1b;由于涉及到底层技术&#…

新160个crackme - 089-fornixcrackme1

运行分析 需要破解Name和Serial PE分析 ASM程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 ida搜索找到关键字符串 动态分析关键函数&#xff0c;逻辑如上图&#xff0c;通过Name计算得到char_1&#xff0c;亦或后对比Serial&#xff0c;相等则返回成功信息 分析…

Python爬虫系列(一)

目录 一、urllib 1.1 初体验 1.2 使用urllib下载网页、图片、视频等 1.3 反爬介绍 1.4 请求对象定制 1.5 get请求的quote方法 1.6 多个参数转成ascii编码 1.7 post请求 1.8 综合案例演示 一、urllib 1.1 初体验 # urllib是python默认带的&#xff0c;无需额外下载 i…

动态规划-回文串问题——5.最长回文子串

1.题目解析 题目来源&#xff1a;5.最长回文子串——力扣 测试用例 2.算法原理 1.状态表示 判断回文子串需要知道该回文子串的首尾下标&#xff0c;所以需要一个二维数组且数据类型为bool类型来存储每个子字符串是否为回文子串&#xff0c; 即dp[i][j]:以第i个位置为起始&a…

源代码安全管理:深信达SDC沙盒技术解密

在数字化时代&#xff0c;源代码安全管理的重要性日益凸显&#xff0c;它不仅关系到企业的核心竞争力&#xff0c;更是企业智慧成果的结晶。深信达的SDC沙盒防泄密软件以其独特的技术优势&#xff0c;为源代码安全提供了全方位的保护。 源代码安全管理的重要性 源代码作为企业…

Virtuoso使用layout绘制版图、使用Calibre验证DRC、LVS、PEX抽取RC

1 绘制版图 1.1 进入Layout XL 绘制好Schmatic后&#xff0c;在原理图界面点击Launch&#xff0c;点击Layout XL进入版图绘制界面。 1.2 导入元件 1、在Layout XL界面左下角找到Generate All from Source。 2、在Generate Layout界面&#xff0c;选中“Instance”&#…

YOLO11改进 | Neck | 有效提升小目标检测效果,附完整代码结构图【论文必备】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 本文给大家带来的教程是将YOLO11的卷积替…