• C++ 之 面向对象基础知识


    面向过程设计

    实际上就是模块化编程,简单来说就是程序 = 数据结构 + 函数,但是函数和变量是分开的也就是说property和behavior是分割的。

    graph LR; A((结构化程序设计)) --> B((模块化编程))

    面向对象设计

    graph LR; A[一类事物] -->|抽象| B[共同属性 ] B --> C[数据结构] A -->|抽象| D[行为/操作] D --> E[函数] C -->|封装| F[类] E -->|封装| F[类]

    类的定义

    class 类名
    {
        访问范围说明符:
            成员变量1
            成员变量2
            ···
            成员函数声明1
            成员函数声明2
        访问范围说明符:
            更多成员变量1
            更多成员变量2
            ···
            更多成员函数声明1
            更多成员函数声明2  
    };
    

    复制构造函数

    class X{};
    X::X(X &);
    X::X(const X &);
    X::X(X); //该构造函数形式不允许存在
    

    作用

    1. 当用一个对象去初始化同类的另一个对象时。
    2. 如果某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用。
    3. 如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数被调用

    类型转换构造函数

    目的:

    • 实现类型的自动转换
    • 特点
    • 只有一个参数
    • 不是复制构造函数
    • 编译系统会自动调用

    转换构造函数
    建立一个临时对象/临时变量

    Exsample :

    class Complex{
    public:
        double real, imag;
        Complex(int i){
            cout << "IntConstructor called" <<endl;
            real = i;
            imag = 0;
        }
        Complex(double r,double i) {
            real = r;
            imag = i;
            }
    };
    
    int main(){
        Complex c1(7,8);
        Complex c2=12;
        c1=9;//9被自动转换成一个临时Complex对象
        cout<< c1.real<<","<<c1.imag <<endl;
        return 0;
    }
    

    静态成员变量与函数

    • 普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。
    • 普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。

    sizeof 不计算静态成员变量, 静态函数不可以访问非静态成员变量。

    访问方法:

    1. 类名::成员名
      CRectangle::PrintTotal();
    2. 对象名.成员名
      CRectangle r; r.PrintTotal();
    3. 指针->成员名
      CRectangle*p=&r; p->PrintTotal();
    4. 引用.成员名
      CRectangle&ref=r; int n=ref.nTotalNumber;

    友元

    一个类的友元函数可以访问该类的私有成员, 但是友元类之间的关系,不能传递,不能继承
    实现方法:

    1. 将一个类的成员函数(包括构造,析构函数)定义为另一个类的友元函数
    class CCar;//提前声明CCar类,以便后面CDriver类使用
    class CDriver{
    pubic:
        void ModifyCar(CCar*pCar);//改装汽车
     };
    class CCar{
    private:
        int price;
        friend int MostExpensiveCar(CCar carsl,int total);//声明友元
        friend void CDriver:ModifyCar(CCar*pCar); //声明友元
    };
    
    1. 将一个类定义为另一个类的友元类
    class CCar{
    private:
        int price;
        friend class CDrpver/声明CDriver为友元类
    };
    class CDriver{
    public:
        CCar myCar;
        void ModifyCar(){//改装汽车
            myCar.price +=1000; //CDriver是CCar的友元类可以访问其私有成员
        }
    };
    

    静态成员变量&函数

    注意静态变量&函数可以直接通过类进行调用,同时静态成员变量需要在类外*.cpp文件中进行初始化
    头文件中

    class chart{
    public:
    	static int chartCount;
    	static initChartCount(){
    		chartCount = 0;
    	}
    };
    

    源文件中

    int chart::chartCount = 0;
    void test(){
    	chart::initChartCount();
    }
    

    成员对象和封闭类

    成员对象:一个类的成员变量是另一个类的对象
    封闭类(Enclosing): 包含成员对象的类

    当封闭类对象生成时

    1. 执行所有成员对象的构造函数
    2. 执行封闭类的构造函数

    成员对象的构造函数调用顺序

    • 和成员对象在类中的说明(定义)顺序一致
    • 与在成员初始化列表中出现的顺序无关

    当封闭类的对象消亡时

    1. 先执行封闭类的析构函数
    2. 执行成员对象的析构函数

    构造函数和析构函数的调用顺序相反

    派生类

    class 派生类 : public 基类{}
    

    构造函数以及析构函数调用顺序

    创建派生类的对象时,执行派生类的构造函数之前:

    • 调用基类的构造函数, 初始化派生类对象中从基类继承的成员
    • 调用成员对象类的构造函数

    初始化派生类对象中成员对象执行完派生类的析构函数后:

    • 调用成员对象类的析构函数
    • 调用基类的析构函数

    析构函数的调用顺序与构造函数的调用顺序相反

    public继承的赋值兼容规则

    class base{};
    class derived:public base{};
    base b;
    derived d;
    
    1. 派生类的对象可以赋值给基类对象 b=d
    2. 派生类对象可以初始化基类引用 base&br=d
    3. 派生类对象的地址可以赋值给基类指针 base*pb=&d

    访问范围说明符

    基类的private成员:可以被下列函数访问

    • 基类的成员函数
    • 基类的友员函数

    基类的public成员:可以被下列函数访问

    • 基类的成员函数
    • 基类的友员函数
    • 派生类的成员函数
    • 派生类的友员函数
    • 其他的函数

    基类的protected成员:可以被下列函数访问

    • 基类的成员函数
    • 基类的友员函数
    • 派生类的成员函数可以访问当前对象的基类的保护成员

    注意:

    1. 如果在派生类中有基类一样的变量或函数,则使用域运算符进行区分

    继承关系和复合关系

    继承:“是”关系。

    class CCircle : public CPoint {
        double r;
    }
    
    • 基类A,B是基类A的派生类。
    • 逻辑上要求:“一个B对象也是一个A对象”。

    复合:“有”关系。

    class CCircle {
        double r;
        CPoint center;
    }
    
    • 类C中“有”成员变量k,k是类D的对象,则C和D是复合关系
    • 一般逻辑上要求:“D对象是C对象的固有属性或组成部分”。

    复合关系的使用

    正确写法:

    1. 为“狗”类设一个“业主”类的对象指针;
    2. 为“业主”类设一个“狗”类的对象指针数组。
    class CMaster;//CMaster必须提前声明,不能先写CMaster类后写Cdog类
    class CDog{ 
        CMaster * pm;
    };
    class CMaster{
        std::vector<CDog *> dogs
    }
    
    任世事无常,勿忘初心
  • 相关阅读:
    Raft协议备注
    领域建模笔记
    Spark编程模型
    Spark如何删除无效rdd checkpoint
    Parquet 列式存储格式
    SpringBoot中ConditionalOnClass注解的原理
    SpringBoot定制Sevlet容器原理
    分析JDK的动态代理原理
    简述SpringCloud底层原理
    简述SpringCloud框架
  • 原文地址:https://www.cnblogs.com/FlameBlog/p/14715319.html
Copyright © 2020-2023  润新知