首页 > 编程语言 >C++中类的三的特性是什么?什么是构造函数和析构函数?它们的作用是什么?

C++中类的三的特性是什么?什么是构造函数和析构函数?它们的作用是什么?

时间:2024-11-05 14:19:37浏览次数:3  
标签:和析构 函数 子类 多态 C++ 调用 父类 构造函数

1) C++ 中类的三大特性是什么?请简要解释。

C++中类的三大特性是封装、继承和多态

一、封装

封装是将数据和操作数据的方法封装在类中,对外部隐藏类的内部实现细节。通过将数据成员设为私有(private),并提供公有的(public)成员函数来访问和修改这些数据,从而实现对数据的保护和控制。这样可以防止外部代码直接访问和修改类的内部数据,提高了代码的安全性和可维护性。

二、继承

继承允许一个类(子类或派生类)继承另一个类(父类或基类)的属性和方法。子类可以继承父类的公有和保护成员,同时可以添加自己的新成员或重写父类的成员函数。

继承的好处:可以减少重复的代码

class A : public B;

A 类称为子类 或 派生类

B 类称为父类 或 基类

继承方式:

凡是基类中私有的,派生类都不可访问。

基类中除了私有的成员,其他成员在派生类中的访问属性总是 以(继承方式,基类的访问属性)中 安全性高的方式呈现。(安全性级别:私有>保护>公有)

继承权限会缩小父类中的成员在子类中的权限,不会扩大成员的权限

子类继承父类其中私有成员只是被隐藏了,但是还是会继承下去

继承同名成员处理方式:

访问子类同名成员 直接访问即可

访问父类同名成员 需要加作用域

  • 当父类和子类中有同名函数时,子类中的函数会将父类中的同名函数隐藏(函数隐藏);如果此时想通过子类对象访问父类对象,需要作用域
  • 父类对象不可以访问子类对象中的成员变量,因为创建父类对象不会创建子类对象
三、多态
函数重写(覆盖)

定义:子类重新定义父类中有相同名称,返回值和参数的虚函数,主要在继承关系中出现。

父类中的fun函数是虚函数,子类中有返回值,名字 参数 相同的fun函数,那么子类中的fun函数(无论加不加virtual)都是虚函数

基本条件:

  • 重写的函数和被重写的函数必须都虚(virtual)函数,并分别位于基类和派生类中
  • 重写的函数和被重写的函数,返回值,函数名和函数参数必须完全一致;

函数隐藏:子类中只要和父类函数名字相同不是重写,一定是函数隐藏

多态的基本概念:
  • 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
  • 动态多态: 派生类和虚函数实现运行时多态(父类的指针或引用指向子类对象,并且调用子类的重写函数)

静态多态和动态多态区别:

  • 静态多态的函数地址早绑定 - 编译阶段确定函数地址
  • 动态多态的函数地址晚绑定 - 运行阶段确定函数地址

父类指针或引用指向子类对象时,函数隐藏不会调用子类中的函数而是调用父类中的函数

调用的函数是隐藏函数时,调用函数的指针或对象是什么类型调用哪里的函数

总结:

多态满足条件

  • 有继承关系
  • 子类重写父类中的虚函数

多态使用条件

  • 父类指针或引用指向子类对象

重写:函数返回值类型 函数名 参数列表 完全一致称为重写

多态的实现

为了实现 C++ 的多态,C++ 使用了一种动态绑定的技术。这个技术的核心是虚函数表。下面介绍虚函数表是如何实现动态绑定的。

类的虚函数表
  • 每个包含了虚函数的类都包含一个虚表(存放虚函数指针的数组)。
  • 当一个类(B)继承另一个类(A)时,类 B 会继承类 A 的函数的调用权。所以如果一个基类包含了虚函数,那么其继承类也可调用这些虚函数,换句话说,一个类继承了包含虚函数的基类,那么这个类也拥有自己的虚表。
  • 以下的代码。类 A 包含虚函数vfunc1,vfunc2,由于类 A 包含虚函数,故类 A 拥有一个虚表。
class A {
public:
    virtual void vfunc1();
    virtual void vfunc2();
    void func1();
    void func2();
private:
    int m_data1, m_data2;
};
class B : public A{//此时类B也拥有自己的虚表
};


纯虚函数和抽象类

纯虚函数语法:virtual 返回值类型 函数名 (参数列表)= 0 ;

当类拥有纯虚函数,这个类也称为抽象类(一般作为基类)

抽象类特点:

  • 无法实例化对象(抽象类不能创建对象)
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
  • 纯虚函数在虚表中存放的是 0

虚函数在虚表中存放的是函数地址

虚析构和纯虚析构:

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码(如果不加virtual将父类的析构改为虚析构或者纯虚析构 子类的析构会将父类的析构隐藏 从而造成内存泄露)

解决方式:将父类中的析构函数改为虚析构或者纯虚析构

父类指针指向子类对象,只能调用父类成员函数

虚析构和纯虚析构共性:

  • 可以解决父类指针释放子类对象
  • 都需要有具体的函数实现

虚析构和纯虚析构区别:

  • 如果是纯虚析构,该类属于抽象类,无法实例化对象

虚析构语法: virtual ~类名(){}

纯虚析构语法: virtual ~类名() = 0;

2)什么是构造函数和析构函数?它们的作用是什么?

构造函数

作用:在创建对象的时候,给对象的成员变量赋值,创建对象的时候自动调用,无需手动调用

当没有实现构造函数的时候,编译器会自动提供默认的无参构造

创建对象一定会调用构造函数,当实现了任意一个构造函数时,编译器则不提供默认构造函数

语法:

  1. 没有返回值也不写void
  2. 名字与类名相同
  3. 有参数,可以重载
  • 有参构造函数是必须的,如果你定义了至少一个有参的构造函数,C++编译器不会为你创建一个默认的无参构造函数
  • 无参(默认)构造函数是可选的,如果你没有定义任何构造函数,C++编译器将为你创建一个无参构造函数。它不执行任何操作,只是创建一个空的对象

构造函数三种调用方式:

  1. 括号法
  2. 显式法
  3. 隐式法 (可以通过关键字explicit避免隐式法调用构造函数)
class pointer {
    int* p;
public:
    pointer(int n) {
        p = new int[n];
        cout << "有参" << endl;
    }
    pointer() {
        cout << "无参" << endl;
    }
};
int main() {
    pointer p1(4);//括号法
    pointer p2 = 4;//隐式法    
    pointer p3 = pointer(4);//显式法
}


析构函数(一个类只能定义一个析构)
  1. 在对象被释放的时候调用
  2. 没有实现析构函数的时候编译器会自动提供析构函数(什么也不做)
  3. 没有返回值 不写void
  4. 析构函数不可以有参数,因此不可以发生重载
  5. 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次

语法:~类名(){}

class pointer {
    int* p;
public:
  //创建对象时用构造函数
    pointer() {
        p = nullptr;
    }
    pointer(int n) {
        p = new int[n];
    }
  //释放对象时用析构函数
    ~pointer() {
      //释放对象时用析构函数,释放成员变量指向的堆区内存
        if (p)delete[]p;
    }
};
int main() {
  //在作用域结束时,被释放,被释放的时候调用析构函数
    pointer p1(3);
    pointer* p2 = new pointer(3);
    delete p2;//delete p2会先调用p2的析构函数然后在释放p2
}


拷贝构造函数

拷贝构造(参数类型为引用类型):通过当前的对象复制出来一份一模一样的对象 拷贝构造的调用时机:通过对象初始化对象的时候会调用拷贝构造

  1. 通过已经存在的对象初始化新的对象
  2. 函数参数以值的形式传递的时候 (实参初始化形参)
  3. 函数的返回值以值的形式传递的时候

参数或者返回值为引用时,可以避免调用拷贝构造

(如果拷贝构造的参数不是引用,则会陷入无限递归,如果不加const,可能出现形参修改实参的情况)

  • 浅拷贝:就是简单的赋值操作(浅拷贝问题:如果有指针指向堆区内存时,不同对象的指针成员指向同一块堆区内存,在对象释放的时候,该堆区内存会被释放两次,当一个对象修改堆区内存时,另一个对象也随着变化。)
  • 深拷贝:申请相同大小的堆区内存,保证两个对象的堆区的值相同(如果属性有堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来问题)

标签:和析构,函数,子类,多态,C++,调用,父类,构造函数
From: https://blog.csdn.net/SUN_Gyq/article/details/143492669

相关文章

  • 每天两个知识点 拷贝构造函数和赋值运算符重载的作用&C++模板及其类型
    1)拷贝构造函数和赋值运算符重载的作用拷贝构造函数(CopyConstructor)和赋值运算符重载(AssignmentOperatorOverload)是C++中处理对象复制和赋值的两个重要机制。拷贝构造函数:拷贝构造函数是一个特殊的构造函数,它用于创建一个新对象,并将其初始化为另一个同类型对象的副本。......
  • 大话C++:第27篇 Lambda表达式
    1Lambda表达式介绍在C++中,lambda表达式(也称为闭包)是一种可以定义匿名函数对象的便捷方式。它们能够捕获所在作用域中的局部变量,并且可以在需要函数对象的地方使用。Lambda表达式为C++提供了更简洁、更灵活的函数式编程方式。Lambda表达式的基本语法如下:[capture](parameter......
  • C++ OpenCv二值化找圆心坐标
    思路:图像转为灰度图,然后二值化得到只有0或255的点坐标,此处圆是黑点,所以添加所有像素值为0的坐标。在这些坐标中找到圆上最左边、最顶端、最右边、最底端的四个点,这时可求出圆心坐标。 .cpp文件#include<opencv2/opencv.hpp>#include<iostream>#include<cstdlib>#include......
  • (3)---【C语言】【GL库】【计算机图形学】DEV C++ 平台openGL库 下的画线图案设计 房
    声明:        由于本人是一名学生,现阶段还要完成学业,所以我们每周假期再回!谢谢大家理解和支持!上篇上手实践  运行结果 实现代码#include<windows.h>#defineGLUT_DISABLE_ATEXIT_HACK//处理不同系统的配置问题的宏#include<GL/glut.h>#include<std......
  • 每日OJ题_牛客_相差不超过k的最多数_滑动窗口_C++_Java
    目录牛客_相差不超过k的最多数_滑动窗口题目解析C++代码Java代码牛客_相差不超过k的最多数_滑动窗口相差不超过k的最多数_牛客题霸_牛客网(nowcoder.com)描述:        给定一个数组,选择一些数,要求选择的数中任意两数差的绝对值不超过 k 。问最多能选择多少......
  • 【c++篇】:深入剖析vector--模拟实现属于自己的c++动态数组
    ✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨✨个人主页:余辉zmh–CSDN博客✨文章所属专栏:c++篇–CSDN博客文章目录前言一.`vector`类的默认成员函数整体框架构造函数析构函数拷贝构造函数赋值运算符重载函数测试二.`vector`......
  • C++ 逆序乘积式
     题目描述【问题描述】若两个正整数的乘积,等于两正整数各自逆序后的乘积,则称其为逆序乘积式。编写程序读入两个正整数,然后判断这两个正整数能否构成逆序乘积式。假设两个正整数的乘积不会超过int数据类型的表示范围。【输入形式】从控制台输入以一个空格分隔的两个正整数......
  • HarmonyOS 开发实践——基于HAR的跨模块C++头文件引用
    ......