【自用】面向对象C++笔记

面向对象

对象,就是对问题中的事物的抽象
面向对象:就是把现实中的事物都抽象为“对象”。每个对象是唯一的,且都可以拥有它的属性与行为。我们就可以通过调用这些对象的方法、属性去解决问题。

  • 对象

    对象是由数据(描述事物的属性)和作用于数据的操作(体现事物的行为)组成的封装体,描述客观事物的一个实体,是构成系统的基本单元。

  • 类是对一组有相同数据和相同操作的对象的定义,是对象的模板,其包含的方法和数据描述一组对象的共同行为和属性。类是在对象之上的抽象,对象则是类的具体化,是类的实例。类可有其子类,也可有其他类,形成类层次结构。

  • 类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间

面向对象程序设计(OOP)的核心思想是数据抽象继承动态绑定

  • 使用数据抽象, 我们可以将类的接口与实现分离(封装)。
  • 使用继承, 我们可以定义相似的类型并对其相似关系建模。
  • 使用动态绑定, 可以在一定程度上忽略相似类型的区别, 而以统一的方式使用它们的对象(多态)

面向对象的基本特征

(76条消息) 什么是面向对象,它的三个基本特征:封装、继承、多态_面向对象的三个基本特征_冰棍hfv的博客-CSDN博客

[(86条消息) 【C++ 语言】面向对象 ( 继承 | 重写 | 子类调用父类方法 | 静态多态 | 动态多态 | 虚函数 | 纯虚函数 )_c++ 子类重写父类方法_韩曙亮的博客-CSDN博客](https://blog.csdn.net/shulianghan/article/details/99690475#:~:text=%2F%2F声明 Parent1 父类对象%2C 为其赋值一个 Child 对象 Parent1* parent1,%3D new Child()%3B %2F%2F此时调用其 parent_method 方法%2C 调用的是父类的方法 parent1->parent_method()%3B)

封装

封装(encapsulation)即信息隐蔽。它是指在确定系统的某一部分内容时,应考虑到其它部分的信息及联系都在这一部分的内部进行,外部各部分之间的信息联系应尽可能的少。

public/private访问范围
  • 用户代码(类外)可以访问public成员而不能访问private成员;private成员只能由类成员(类内)和友元访问。

  • protected成员可以被**子类对象(也称为派生类)**访问,不能被用户代码(类外)访问。

  • 继承后改变访问属性

    **1.public继承:**基类public成员,protected成员,private成员的访问属性在派生类中分别变成:public, protected, private

    **2.protected继承:**基类public成员,protected成员,private成员的访问属性在派生类中分别变成:protected, protected, private

    **3.private继承:**基类public成员,protected成员,private成员的访问属性在派生类中分别变成:private, private, private

友元函数/友元类

(1)友元函数:在定义一个类的时候,可以把一些函数(包括全局函数和其他类的成员函数)声明为“友元”,这样那些函数就成为该类的友元函数,在友元函数内部就可以访问该类对象的私有成员了

  • 将全局函数声明为友元的写法如下:

    friend int MostExpensiveCar(CCar cars[], int total); //声明友元

  • 将其他类的成员函数声明为友元的写法如下:

    friend void CDriver::ModifyCar(CCar* pCar); //声明友元

但是,不能把其他类的私有成员函数声明为友元。

(2)友元类:一个类 A 可以将另一个类 B 声明为自己的友元,类 B 的所有成员函数就都可以访问类 A 对象的私有成员。在类定义中声明友元类的写法如下:

class CCar
{
private:
    int price;
    friend class CDriver;  //声明 CDriver 为友元类
};
class CDriver
{
public:
    CCar myCar;
    void ModifyCar()  //改装汽车
    {
        myCar.price += 1000;  //因CDriver是CCar的友元类,故此处可以访问其私有成员
    }
};
继承(类的继承)

让某个类型的对象获得另一个类型的对象的属性和方法。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

  1. 继承表示 : C++ 中继承可以使用 “:” 符号 , 格式为 “class 子类名称 : 父类名称{};”

    //父类
    class Parent{};
    //子类
    //继承父类 Parent
    class Child : Parent{};
    
  2. 继承作用域 : 继承可以指定作用域 , private , protected , public , 如果不写作用域 , 那么该继承就是默认私有继承 ; 作用域符号写在 冒号之后 , 父类名称之前 ;

  3. 私有 ( private ) 继承 : 如果继承的作用域是私有的 ( private ) , 那么继承的所有的方法都是私有的 , Parent 中的 public 和 protected 方法会变成私有的 , 外部无法访问该方法 ;

  4. C++ 多继承 : Java 中只能进行单继承 , 但是在 C++ 中是可以继承多个父类的 ; 在多继承时 , 使用 “,” 将多个父类分隔即可 ;多继承中 , 每个父类的作用域都可以单独指定;

    //子类
    //继承父类 Parent
    //继承作用域 : 默认私有继承 private 
    class  Child : private Parent, public Parent1{};
    
  5. 子类重写父类方法 : 如果继承的两个父类有相同的方法 , 在子类又定义了一个相同的方法 , 这就是重写父类的方法 ;

  • 调用子类重写的 “parent_method” 方法 , 其执行的是子类重写的方法

    外部通过子类调用父类方法 : 如果调用的方法在子类中没有重写 , 那么调用的就是父类的方法

  • //父类
    class Parent1 {
    public:
    	void parent_method() {
    		cout << " Parent1 parent_method " << endl;
    	}
    
    	void parent_method1() {
    		cout << " Parent1 parent_method1 " << endl;
    	}
    };
    
    //子类
    //继承父类 Parent
    //继承作用域 : 默认私有继承 private 
    class Child : private Parent, public Parent1 {
    public:
    	void parent_method() {
    		cout << " Child parent_method " << endl;
    	}
    };
    
    	//在栈内存中创建一个 Child 对象, 并调用其重写的父类的方法
    	Child child;
    	//调用子类重写的父类的方法 结果:child parentmethod
    	child.parent_method();
    
    	//调用子类没有重写的父类方法 结果:parent1 parentmethod1
    	child.parent_method1();
    
  1. 子类中调用父类的方法 : 使用 " 父类名称 :: 方法名() " 进行调用
class Child : private Parent, public Parent1 {
public:
  void parent_method() {
  	//子类中调用父类的方法 , 该操作相当于 Java 中的 super 方法 
  	Parent::parent_method();
  	Parent1::parent_method();

  	cout << " Child parent_method " << endl;
  }
};
  //在栈内存中创建一个 Child 对象, 并调用其重写的父类的方法
  Child child;
  //调用子类重写的父类的方法 结果为:
   /*Parent parent_method
   Parent1 parent_method
   Child parent_method*/
  child.parent_method();
多态

声明 Parent1 父类对象 , 为其赋值一个 Child 对象 , 此时调用其 parent_method 方法 , 调用的是父类的方法 ;

	//声明 Parent1 父类对象 , 为其赋值一个 Child 对象
	Parent1* parent1 = new Child();
	//此时调用其 parent_method 方法 , 调用的是父类的方法,即结果为输出parent...
	parent1->parent_method();
1. 虚函数/重载:

如果必须要调用子类实现的方法 , 这里就需要用到虚函数

new/delete

  1. new是CPP定义的关键字不是函数通过特定的语法可以组成表达式。和 sizeof 不同的是,sizeof 在编译时候就可以确定其返回值。

    • 基本用法:

      int *a = new int[5];
      delete []a;
      //
      class A
      {
      public:
          A(int v) : var(v)
          {
              fopen_s(&file, "test", "r");
          }
          ~A()
          {
              fclose(file);
          }
      
      private:
          int var;
          FILE *file;
      };
      A *obj = new A(10);  //使用 new 创建对象
      delete obj;
      
    • 例子中new关键字的具体工作方式:

      1. (new)调用下面提到的 operator new 标准库函数,传入的参数为 class A 的大小,这里为 8 个字节,至于为什么是 8 个字节,你可以看看《深入 C++ 对象模型》一书,这样函数返回的是分配内存的起始地址,这里假设是 0x007da290。
      2. ( A(10) )上面分配的内存是未初始化的,也是未类型化的,第二步就在这一块原始的内存上对类对象进行初始化调用的是相应的构造函数,即调用 A:A(10); 这个函数,从图中也可以看到对这块申请的内存进行了初始化,var=10, file 指向打开的文件
      3. (A* obj = )最后一步就是返回新分配并构造好的对象的指针,这里 obj就指向 0x007da290 这块内存,obj的类型为类 A 对象的指针。
  2. operator new是cpp的标准库库函数,不是operator重载符,用于分配空间

    缺省情况下,C++在global作用域内提供以下形式的operator new:

    void *operator new(size_t);     //allocate an object
    void *operator delete(void *);    //free an object
    
    void *operator new[](size_t);     //allocate an array
    void *operator delete[](void *);    //free an array
    

    原文链接:https://blog.csdn.net/zqxf123456789/article/details/108431315

    • 如果定义了自定义的operator new/placement new成员函数,一定要对应的定义与之匹配的operator delete/placement delete。
      由于成员函数的名称会掩盖其外围作用域的相同名称,所以如果自定义了operator/placement new,那么标准库版本的operator new就会被掩盖而无法调用。

      例如:

      Employee
      {
      public:
      	static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc); //这个new会掩盖正常的global形式
      	...
      };
      
      Employee* pb = new Employee;  //Error! 正常形式的operator new被掩盖
      Employee* pb = new (std::cerr) Employee; //Correct, 调用Employee的placement new
      
      

命名空间(namespace)

C++中名称(name)可以是符号常量、变量、函数、结构、枚举、类和对象

变量、函数和类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染。命名空间只能全局范围内定义,且可以重定义编译器最终会归类到一起

  1. 命名空间里可以定义变量,也可以定义函数。
    访问a时需要加上域作用限定符(::),即N1::a

    namespace N1
    {
        int a = 10;//定义变量
        int add(int left,int right)//定义函数
        {
             return left+right;
        }
        namespace N2{class X;}//可以嵌套,调用时使用N1::N2::X
    }
    
    void N1::func()//成员函数 在外部定义的时候 记得加作用域
    {
        //访问命名空间的数据不用加作用域
        cout<<"func遍历a = "<<a<<endl;
    }
    
  2. 使用using namespace引入命名空间;也可以using N1::a引入命名成员

    例如using namespace std

类与接口

堆与栈

临时变量

引用类型

GC

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
项目:使用 JavaScript 编写的杀死幽灵游戏(附源代码) 杀死鬼魂游戏是使用 Vanilla JavaScript、CSS 和 HTML 画布开发的简单项目。这款游戏很有趣。玩家必须触摸/杀死游荡的鬼魂才能得分。您必须将鼠标悬停在鬼魂上 - 尽量得分。鬼魂在眨眼间不断从一个地方移动到另一个地方。您必须在 1 分钟内尽可能多地杀死鬼魂。 游戏制作 这个游戏项目只是用 HTML 画布、CSS 和 JavaScript 编写的。说到这个游戏的特点,用户必须触摸/杀死游荡的幽灵才能得分。游戏会根据你杀死的幽灵数量来记录你的总分。你必须将鼠标悬停在幽灵上——尽量得分。你必须在 1 分钟内尽可能多地杀死幽灵。游戏还会显示最高排名分数,如果你成功击败它,该分数会在游戏结束屏幕上更新。 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox。要玩游戏,首先,单击 index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值