面向对象CPP

面向对象编程(OOP: Object-Oriented Programming

它的本质是,定义自己的数据类型,就可根据具体的问题提出解决方案。

  • 类是定义数据类型的代码块
  • 类的名称就是自定义数据类型的名称
  • 类类型的数据项,称为对象
  • 创建变量,以存储自定义数据类型的对象时,就要使用类类型名称
  • 类是按照现实生活中的实体来设计对象的行为,是直观并易于理解的
  • 类提供了一种解决方案

万事万物都皆为对象,对象上有其属性和行为

具有相同性质的对象,我们可抽象称为类,人属于人类,车属于车类

封装

对象由两部分组成:属性 + 行为

  • 属性:一组数据值,作为类的成员变量,指定对象的属性
  • 行为:一组操作,作为类的成员函数,指定对象的行为

把这些数据值和函数打包到一个对象中,称为 封装。

如何定义和使用类?

封装 - 数据隐藏 - 隐藏内部实现

  • 数据权限控制
  • 隐藏对象中的数据,可禁止直接访问数据,
    但可通过对象的成员函数来访问
  • 数据隐藏有助于维护对象的完整性,能够确保对象的内部状态(及其所有成员变量的组合)在任何时候都是有效的
  • 数据隐藏与精心设计的接口结合起来,
    能够在修改对象的内部表示(对象的状态)及其成员函数的实现(对象的行为)时,
    不必修改程序的其余部分。
  • 数据隐藏降低使用类的代码之间的耦合性
class ClassName{
private:
    //...
protected:
	//...
public:
    //...
	
    //Constructor
    ClassName(){ }//无参构造 普通
    explicit ClassName(dataType para){ }//有参构造"只有一个参数" 普通
    ClassName(const ClassName& obj){ }//拷贝构造
    
    dataType property_1;
    dataType property_2;
    dataType property_3;
    ClassName(dataType para_1, dataType para_2, dataType para_3)
        : property_1(para_1), property_2(para_2), property_3(para_3){//成员初始化列表
        
    }
    
    //Destructor
    ~ClassName(){ }
}

void useClassNameExample(){
    /* 1. 括号法 */
    ClassName obj_1;//调用默认构造函数 即无参构造
    ClassName obj_2(value);//调用有参构造函数
    ClassName obj_3(obj_1);//调用拷贝构造函数
    
    /* 2. 显示法 */
    ClassName obj_1;
    ClassName obj_2 = ClassName(value);
    ClassName obj_3 = ClassName(obj_1);
    
    /* 3. 隐式转换法 */
    ClassName obj_2 = value;
    ClassName obj_3 = obj_1;
}
  • 类名称

    • ClassName 大写名称
  • 成员权限管理

    • private - 默认
    • protected
    • public
  • 构造函数

    • 构造函数名称 ClassName 与类名称一致

    • 两种分类方式

      1. 按参数分为
        1. 无参构造 ClassName( ) { }
        2. 有参构造 ClassName(dataType para){ }
      2. 按类型分为
        1. 普通构造
        2. 拷贝构造 ClassName(const ClassName& obj){ }
    • 三种调用方式:

      1. 括号法【简洁 + 清晰】 - 推荐
      2. 显示法【过于详细】
      3. 隐式转换法【过于简洁】
    • default - 定义默认构造函数
      ClassName( ){ } <==等价于==> ClassName() = default

    • explicit - 显式转换

      对只有一个参数的构造函数,只要使用 explicit 关键字,

      就可避免把参数的数据类型转换为类类型。

      类的构造函数只要一个参数是有问题的,
      因为编译器可使用此构造函数把参数的类型隐式转换为类类型。

  • 析构函数

    • 析构函数名称 ~ClassName 与类名称一致的前提下,
      在名称前加上符号 ~
  • 成员初始化列表

  • 访问私有类成员

    • 访问器函数 - getMyMember( ) - getter( )

      例外,bool 成员变量的访问器常常被命名为 isMyMember( ),即,布尔成员变量 valid 的 getter 常常被命名为 isValid( ) 而不是 getValid( )

    • 更改器函数 - setMyMember( ) - setter( )

  • this - 指向调用者本身

  • const - 不能修改

    • 常函数 dataType func(paraList) const{ }
    • 常对象 const ClassName obj;
    • mutable - 特殊可变
  • friend - 访问另一个类中私有成员

    1. 全局函数做友元
    2. 类做友元
    3. 成员函数做友元
  • static

    • 静态成员变量
      1. 所有对象共享同一份数据
      2. 在编译阶段分配内存
      3. 类内声明,类外初始化 - 作用域解析运算符 ::
    • 静态成员函数
      1. 所有对象共享同一个函数
      2. 静态成员函数只能访问静态成员变量

继承

继承是根据一个类型定义另一个类型的能力。

  • 在派生类中重新定义基类的函数,称为 重写

    重新定义继承下来的函数,可使它们在自己的环境下更有意义

  • 自由定义适合于自己类型的新特性

  • 复用现有代码

class subclassName : inheritanceMode parentClass{
    
}

class A{
public:
    dataType property_1;
protected:
    dataType property_2;
private:
    dataType property_3;
}

class B : public A{//公共继承
public:
    dataType property_1;
protected:
    dataType property_2;
}

class B : protected A{//保护继承
protected:
    dataType property_1;
    dataType property_2;
}

class B : private A{//私有继承
private:
    dataType property_1;
    dataType property_2;
}

void example(){
    B b;
    b.property_1//访问的是子类B中的属性
    b.A::property_1//访问的是父类A中的属性
}

//多继承语法
class sonClass: InheritanceWay1 parentClass1, InheritanceWay2 parentClass2 ......{
    
}
//虚继承
class subclassName : inheritanceMode virtual parentClass{
    
}
  • 继承方式 inheritanceMode - 成员权限变化(访问级别)

    • 公共继承 public
    • 保护继承 protected
    • 私有继承 private
  • 继承内容

    父类中所有非静态成员属性都会被子类继承下去,

    父类中私有成员属性,是被编译器给隐藏

    因此是访问不到,但是确实被继承下去

  • 继承中构造和析构顺序

    继承中先调用父类构造函数,再调用子类构造函数,

    析构顺序与构造相反

  • 继承成员同名处理方式 - 作用域解析运算符 ::

  • 继承同名静态成员处理方式 - 作用域解析运算符 ::

  • 多继承 - 不建议 但可继承接口

  • 菱形继承/重复继承问题 - 虚继承

多态

多态性表示在不同的时刻有不同的形态。

  • C++中的多态性总是涉及使用 指针引用调用对象的成员函数

  • 这种函数调用在不同的时刻有不同的效果——函数调用有多种不同的形式

  • 此机制仅适用派生于公共类型的对象

  • 多态性仅用于共享一个公共基类的类层次结构

  • 多态性意味着,属于一组继承性相关的类的对象可通过 基类指针 和 引用 来传送和操作。

  • 通过指针调用哪个函数并不是在编译程序时确定的,而是在程序执行时才确定。
    因此,同一个函数调用会根据指针指向的对象完成不同的操作

  • 常常不能事先确定要处理哪种类型的对象,即在设计或编译期间不能确定类型,
    只能在运行期间确定

  • 改写对象行为

class Base{
public:
    virtual void func() = 0;//纯虚函数
    
    virtual ~Base(){//虚析构函数
        cout << "virtual destructor" << endl;
    }
    
    virtual ~Base() = 0;//纯虚析构函数
}

Base::~Base(){
    cout << "pure virtual destructor" << endl;
}

class Derive_1 : public Base{
public:
    virtual void func(){
        cout << "rewrite in Derive_1" << endl;
    }
}

class Derive_2{
public:
    virtual void func(){
        cout << "rewrite in Derive_2" << endl;
    }
}

class Derive_3{
public:
    virtual void func(){
        cout << "rewrite in Derive_3" << endl;
    }
}

void example(){
    Base* base = new Derive_2;
    base->func();// "rewrite in Derive_2""
    
    delete base;
    base = NULL;
}
  • 多态的分类

    • 静态多态

      函数重载 和 运算符重载 属于静态多态 - 复用函数名

    • 动态多态

      派生类 和 虚函数实现运行时多态

    • 两者的区别

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

    1. 存在继承关系

    2. 子类重写父类中的虚函数

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

  • 使用多态

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

  • 纯虚函数 和 抽象类

    在多态中,通常父类中虚函数的实现是毫无意义的,
    主要都是调用子类重写的内容。

    因此,可以将虚函数改为纯虚函数。

    纯虚函数语法:virtual returnType functionName(Parameter list) = 0

    当类中有了纯虚函数,这个类也称为抽象类

    抽象类特点:

    • 无法实例化对象
    • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
  • 虚析构 和 纯虚析构

    多态使用时,如果子类中有属性开辟到堆区,
    那么父类指针在释放时无法调用到子类的析构代码,
    从而导致内存泄漏

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

    虚析构和纯虚析构共性:

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

    虚析构和纯虚析构区别:

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

    虚析构语法:

    • virtual ~ClassName( ){ //code...}

    纯虚析构语法:

    1. virtual ~ClassName() = 0
    2. ClassName::~ClassName(){ //code...}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值