IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 一文记录C++面向对象基本要点 -> 正文阅读

[C++知识库]一文记录C++面向对象基本要点

面向对象和面向过程

面向过程:分而治之,大问题分解为小问题,一个一个解决。

面向对象:抽象,把数据和函数抽象为属性和行为,封装到一类对象里。

面向对象

  • 封装
  • 继承
  • 多态

成员变量一般都是private,函数方法(接口)一般都是public

构造函数作用:对对象的成员进行初始化。可以重载。如果没有写,系统会默认生成一个无参无内容的构造函数。

按形式:无参、有参

按功能:普通、拷贝

自己不屑拷贝构造函数时,编译器会默认提供,复制全部成员。拷贝构造函数的参数不可以写自身的类,否则会引发递归,应该用引用。

析构函数:对象销毁的时候,会执行,来释放资源。

创建对象时,先调用父类的构造函数,销毁对象时,先调用子类的析构函数。

栈中创建的对象,后创建的先销毁。

返回值优化:RVO(Return Value Optimization)\ Release版本NRVO(Named Return Value Optimization)

-fno-elide-constructors(取消这个优化)

在这里插入图片描述

深拷贝和浅拷贝

浅拷贝:直接复制变量的值。

深拷贝:重新申请一个内存,放入拷贝的值。

初始化列表语法


class person{
private:
    int m_a;
    double m_b;
    char m_c;
    const int m_d;
public:
    person(int a, double b, char c, int d) : 
    m_a(a), 
    m_b(b), 
    m_c(c),
    m_d(d){
        
    }
};

/*
对于const这种,不可以在构造函数内赋值,可以通过列表初始化赋值
*/


类对象作为类成员的构造顺序和类字段的顺序一致,析构顺序和字段顺序相反。

静态成员

  • 静态数据
  • 静态函数

所有类共享这一个成员。

静态数据只能在类内声明,类外定义。

静态函数不能访问类内非静态数据。

单例设计模式

定义:一个类的对象在一个程序中只能存在一个。

方法:

  1. 私有化默认构造函数
  2. 创建一个静态实例
  3. 提供静态获得实例的方法
    1. 懒汉式
    2. 饿汉式
//饿汉式:用的时候直接返回
class person{
private:
    person(){
        
    }
    static person* onePerson;
public:
    static person* getInstance(){
        return onePerson;
    }
};

person* person::onePerson = new person;
//懒汉式:第一次用的时候才创建,再返回
class person{
private:
    person(){
        
    }
    static person* onePerson;
public:
    static person* getInstance(){
        if (onePerson == nullptr){
            onePerson = new person;
        }
        return onePerson;
    }
};

person* person::onePerson = nullptr;

常函数和常对象

class person{
private:
    int m_a;
    double m_b;
    char m_c;
    mutable int e;
    const int m_d;
public:
    person(int a, double b, char c, int d) : 
    m_a(a), 
    m_b(b), 
    m_c(c),
    m_d(d){
        
    }
    //show不可以通过this修改对象的数据
    //此时想修改某些数据,可以在数据前加mutabel
    void show() const {
        e = 100;
    }
};

person p;
const p;
//p的内容不可修改

常对象可以调用常函数,不可以调用普通函数。

友元

友元函数

想让函数访问类的私有成员,可以在类的内部加入如下函数声明

friend returnType func(agr1, ...);

友元类

其他类想访问该类的私有成员,可以在该类中加入其他类的声明

friend class classname;

友元成员函数

其他类的成员函数想访问该类的私有成员,可以在该类中加入其他类的类的成员函数的声明

friend returnType classname::func(arg1, ...);

运算符重载

//类内
returnType operator+(classType& a){
    //...
    return res;
}

//全局
returnType operator+(classType& a, classType& b){
    //...
    return res;
}

t1 + t2;
//t1.operator+(t2);

内存泄漏:用完内存后,忘记释放,导致这块内存不能再使用。

智能指针:自动销毁、释放空间。

编译器默认给一个类添加四个函数

  1. 构造函数(空)
  2. 析构函数(空)
  3. 拷贝构造函数(浅拷贝)
  4. operator= 重载函数(浅拷贝)

函数调用运算符重载

returnType operator()(classType& a){
    //...
    return res;
}

class person{
public:
    person(){
        
    }
    void operator()(){
        cout << "hello world!" << endl;
    }
};

person p;
//p.operator()();
p();
//仿函数,也成为函数对象,本质是对象,而不是函数

运算符重载可以参考字符串类封装

类的自动类型转换和强制类型转换


class person{
private:
    int m_a;
    double m_b;
    char m_c;
    mutable int e;
    const int m_d;
public:
    //这时候 preson p = 10;就会报错
    explicit person(int a){
        m_a = a;
    }
    person(int a, double b, char c, int d) : 
    m_a(a), 
    m_b(b), 
    m_c(c),
    m_d(d){
        
    }
    //show不可以通过this修改对象的数据
    //此时想修改某些数据,可以在数据前加mutabel
    void show() const {
        e = 100;
    }
};

类的继承

继承为了代码复用。

class person{
    
};

class teacher : person{
    
};

好处:

  1. 复用
  2. 维护
  3. 多态的前提

坏处:耦合性增加。好的开发:高内聚,低耦合

内聚:自己完成一件事的能力。

  1. public 公开
  2. private只能本类访问
  3. protected 子类可以访问,类外不能访问

不同继承,会成为派生类的什么成员

  1. 公有继承,不改变
  2. 保护继承,公有的会变保护,不能访问父类私有
  3. 私有继承,公有和保护会变成私有,不能访问父类私有

没有写继承方式,默认私有。

子类将父类中所有成员都继承了,包括私有的。

VS command prompt工具查看类:

  1. 打开当前原文件目录
  2. cl /d1 reportingSingleClassLayout 类名 文件名

子类默认调用父类的无参构造函数。如果父类手动声明了有参构造函数,编译器不会为其自动生成无参构造函数。

子类调用父类方法

son.Base::func();

如果子类中出现父类同名函数,子类会隐藏父类中所有同名函数。(静态成员函数同)

多(重)继承

成员变量和方法容易重名产生歧义。

菱形继承和虚继承

在这里插入图片描述

虚继承

class man : virtual public person{
    
};

class singer : virtual public person{
    
};

class singerMan : public singer, public man{
    
};

vbptr: virtual base pointer(虚基类指针)

虚继承原理:只有一个唯一的成员,通过保存虚基类指针,这个指针指向的是一张表(虚基类表),这个表保存了当前获取到唯一的数据的偏移量。

在这里插入图片描述

对付类的virtual函数继承后重新编写,称为重写、覆写。实现了动态多态。

//不用virtual,子类重名函数的效果
animal aml = new cat();
animal aml1 = new dog();
aml.Speak();
aml1.Speak();
//aml speak
//aml speak
//原因,检查了animal的类型,就会去静态链接


//用virtual后重写,会动态链接,实现了多态
animal aml = new cat();
animal aml1 = new dog();
aml.Speak();
aml1.Speak();
//cat speak
//dog speak


多态:

  1. 静态多态:函数重载、运算符重载等
  2. 动态多态:虚函数重写,父类指针指向子类对象(地址晚绑定、动态多态)

多态前提:

  1. 继承关系
  2. 虚函数
  3. 重写

虚函数机制:

  1. 虚基类表,记录了一些成员的地址
  2. 发生重写,记录子类的,否则记录基类的
  3. vftable记录函数的 vfptr

类中有纯虚函数就是抽象类。抽象类不能创建对象。子类必须重写纯虚函数,否则子类也是抽象类。

class person{
public:
    virtual void speak()=0;
}

虚析构和纯虚析构

#include <iostream>
#include <cstring>

using namespace std;

class animal{
public:
    animal(){
        cout << "animal 构造函数调用了" << endl;
    }
    virtual void speak()=0;
    ~animal(){
        cout << "animal 析构函数调用了" << endl;
    }
};

class cat : public animal{
    char* m_name;
public:
    void speak(){
        cout << "miao" << endl;
    }
    cat(const char* name){
        cout << "cat 构造函数调用了" << endl;
        this->m_name = new char[strlen(name) + 1];
        strcpy(this->m_name,name);
    }
    ~cat(){
        cout << "cat 析构函数调用了" << endl;
        if (this->m_name != nullptr){
            delete[] this->m_name;
            this->m_name = nullptr;
        }
        
    }
};

int main()
{
    animal* c = new cat("smallcat");
    
    delete c;
    
    return 0;
}

//这种情况没有调用cat构造函数直接调用了父类的析构函数
//解决办法
class animal{
public:
    animal(){
        cout << "animal 构造函数调用了" << endl;
    }
    virtual void speak()=0;
    virtual ~animal(){
        cout << "animal 析构函数调用了" << endl;
    }
};
/*
纯虚析构必须在类外写实现
纯虚析构的目的就是让类为抽象类
*/

原理:父类加了virtual之后的析构函数,子类继承后,用父类变量指向子类对象时会有 vfptr指向vftable,vftable存放子类的析构函数的偏移地址。

类似于父类的函数,子类有同名函数,当父类指针指向子类对象的时候,会调用父类的函数,而不是调用子类的同名函数,要想调用子类的函数(即实现多态)就得在父类中声明此函数为虚函数(加 virtual)。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-31 16:26:28  更:2021-07-31 16:27:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/27 19:28:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码