热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Boolanc++面向对象下第二周笔记

在上图中,c继承b,b集成a。在classA中包含m_data1和m_data2以及一个指针。ClassB,继承了A,因此B中除了自己的m_data3外,还包含了classA的所有内容,cla


在上图中,c继承b,b集成a。在class A 中包含m_data1和m_data2以及一个指针。

Class B,继承了A,因此B中除了自己的m_data3外,还包含了class A的所有内容,class C也同理。

在一个类中,若有一个虚函数,内存中有一个指针,若有一万个虚函数,内存中依然有一个指针

在继承关系中,子类不仅继承了父类的所有数据,也继承了父类的函数,准确的说是父类函数中的调用权。没有人可以说清楚父类中的函数占用多大的内存。

 

在上图右边,class A有2个虚函数,2个普通函数,因此,class B中也同样拥有两个虚函数(继承),但是B中重写了其中一个虚函数。另外B中也有一个普通函数(虽然与父类同名,但是是两个不同的函数)class C同理。

因此在ABC三个类中,共有4个虚函数4个普通函数

Class A中的虚指针指向一个虚表(vtbl),虚表中存放的都是函数指针,指向虚函数存放的位置。Class A中有两个虚函数,因此虚表中就有两个指针分别指向两个虚函数。

 

当我们new一个class C的时候就会产生一个指向class C 的指针p,如果我们想通过指针p调用class C的一个虚函数应该怎么调用呢?

思路是这样的,通过指针p找到虚表,然后通过虚表中该函数的位置n(编译时函数出现的顺序),再找到该函数。


总结:满足以下条件,即动态绑定:a. 指针b. 向上转型(指针指的是子类)c.调用虚函数

向上转型解释:例如,class B 继承A。A* pa=new B; pa是指向子类B的指针,但pa是A的对象,由子类B向A转型。



Const 再谈

对于数据,我们有const和non-const两种,对于成员函数,我们也有const和non-const两种。在这种情况下,这四种东西有如下表所示的关系:


在我们设计成员函数的时候,若我们本意是不改变数据而忘了加const的时候,在调用成员函数而对于object加了const的时候(常量对象调用非常量函数),就会发生冲突而导致错误。

 

 

New 和 Delete

Array new 一定要搭配array delete

可以重载operator new、operator delete、operator new[]、operator delete[]

Inline void* operator new (size_t size){ }

Inline void* operator new [](size_t size){}

Inline void operator delete (void* ptr){ }

Inline void operator delete [] (void* ptr){}


本周作业体会

本周作业分为两个部分

(1)      是在上周的基础上添加构造函数和析构函数,然后观察构造和析构函数的调用过程。

这里头文件代码设计如下:

#ifndef__FRUIT__

#define__FRUIT__

#include

usingnamespace std;

classFruit

{

   int no;

   double weight;

   char key;

public:

   Fruit() { cout <<"The defaultFruit ctor.this= "

            <

   virtual ~Fruit() {

            cout <<"The Fruitdtor.this= "

                     <

   }

   void print(){}

   virtual void process(){}

};

 

classApple :public Fruit

{

   int size;

   char type;

public:

   Apple(){cout<<"The default Applector.this= "

            <

   virtual ~Apple() {

            cout <<"The Appledtor.this= "

                     <

   }

   void save(){}

   virtual void process(){}

};

 

#endif

 

源代码如下:

#include

#include"week_5.h"

intmain()

{

   Fruit my_fruit;

   cout <<"*************************" <

   Fruit *p = new Fruit();

   delete p;

   cout <<"*************************" <

   Apple my_apple;

   cout <<"*************************" <

   Fruit *q = new Apple();

   delete q;

   cout <<"*************************" <

   Apple *x = new Apple();

   delete x;

  

}

 

在测试代码中分别设计了五种对象的创建

A)     在栈中创建fruit,

B)     在堆中创建fruit

C)     在栈中创建apple

D)     在堆中创建apple,用父类指针指向它

E)      在堆中创建apple,用子类指针指向它

经编译,结果如下;


结果分析如下:

A)     在栈中创建父类对象时,调用父类构造函数,其析构函数在程序最终结束前才进行调用

B)     在堆中创建父类对象时,调用父类构造函数,再调用析构函数

C)     在栈中创建子类对象时,先调用父类构造函数,再调用子类构造函数,指针指向相同地址。调用析构时同样发生在程序结束时,先调用子类析构函数,再调用父类析构函数。最后调用的析构函数是最先调用的构造函数。

D)     和E)中在堆中创建子类对象时,先调用父类构造函数,再调用子类构造函数,指针指向相同地址,接着先调用子类析构函数,再调用父类析构函数

在D和E中发生的事情一模一样,但是在堆中创建apple,用父类指针指向它时,属于upcast。

 

(1)      作业第二部分为Apple类重载::operator new 和 ::operator delete,并观察调用结果。

主程序如下:

intmain()

{

   Fruit my_fruit;

   cout <<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~" <

   Apple my_apple;

   cout <<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~" <

   Fruit* p = new Fruit();

   delete p;

   cout <<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~" <

   Fruit* q = new Apple();

   delete q;

   cout <<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~" <

   Apple* qq = new Apple[5];

   delete[] qq;

   cout <<"~~~~~~~~~~~~~~~~~~~~~~~~~~~~" <

   Fruit** wk = new Fruit*[5];

   for (int i = 0; i <5; i++)

   {

            wk[i] = new Apple();

   }

   for (int i = 0; i <5; i++)

   {

            delete wk[i];

   }

   delete wk;

   return 0;

}

 

头文件如下:

#ifndef__FRUIT__

#define__FRUIT__

#include

usingnamespace std;

classFruit

{

   int no;

   double weight;

   char key;

public:

   Fruit() { cout <<"The defaultFruit ctor.this= "

            <

   virtual ~Fruit() {

            cout <<"The Fruitdtor.this= "

                     <

   }

   void print(){}

   virtual void process(){}

};

 

classApple :public Fruit

{

   int size;

   char type;

public:

   Apple(){cout<<"The default Applector.this= "

            <

   virtual ~Apple() {

            cout <<"The Appledtor.this= "

                     <

   }

   void save(){}

   virtual void process(){}

   static void* operator new(size_t size);

   static void operator delete(void* ptr,size_tsize);

   static void* operator new[](size_t size);

   static void operator delete[](void*ptr,size_t size);

};

 

inline

void*Apple::operator new(size_t size)

{

   Apple* p = (Apple*)malloc(size);

   cout <<"Apple::new()_size= "<

   return p;

}

 

inline

voidApple::operator delete(void* ptr, size_t size)

{

   cout <<"Apple::delete()_size=" <

   return p;

}

 

inline

voidApple::operator delete[](void* prt, size_t size)

{

   cout <<"Apple::delete[]()_size=" <



推荐阅读
  • 深入探讨栈和队列的应用实例——铁轨问题(Rails, ACM/ICPC CERC 1997, UVa 514)。该问题设定在一个城市火车站,涉及n节车厢从A方向驶入车站,并需按照特定顺序驶出B方向的铁轨。本文将通过算法实现来验证特定顺序的可行性。 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 本文深入探讨了UNIX/Linux系统中的进程间通信(IPC)机制,包括消息传递、同步和共享内存等。详细介绍了管道(Pipe)、有名管道(FIFO)、Posix和System V消息队列、互斥锁与条件变量、读写锁、信号量以及共享内存的使用方法和应用场景。 ... [详细]
  • 本文深入探讨了 Delphi 中类对象成员的核心概念,包括 System 单元的基础知识、TObject 类的定义及其方法、TClass 的作用以及对象的消息处理机制。文章不仅解释了这些概念的基本原理,还提供了丰富的补充和专业解答,帮助读者全面理解 Delphi 的面向对象编程。 ... [详细]
  • 本文详细介绍了Java中的注解功能,包括如何定义注解类型、设置注解的应用范围及生命周期,并通过具体示例展示了如何利用反射机制访问注解信息。 ... [详细]
  • 首先说一下,这是我在CSDN上的第一个文章,其实这个账号早在几年前就申请了,不过当时只是为了下载一个资源,而且也不怎么懂信息技术相关的领域,后来就再也没怎么动过,直到今天我才开始使用这个账号 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 本题要求在一组数中反复取出两个数相加,并将结果放回数组中,最终求出最小的总加法代价。这是一个经典的哈夫曼编码问题,利用贪心算法可以有效地解决。 ... [详细]
  • 本文探讨了C++编程中理解代码执行期间复杂度的挑战,特别是编译器在程序运行时生成额外指令以确保对象构造、内存管理、类型转换及临时对象创建的安全性。 ... [详细]
  • 本文详细介绍了get和set方法的作用及其在编程中的实现方式,同时探讨了点语法的使用场景。通过具体示例,解释了属性声明与合成存取方法的概念,并补充了相关操作的最佳实践。 ... [详细]
  • CentOS 7.6环境下Prometheus与Grafana的集成部署指南
    本文旨在提供一套详细的步骤,指导读者如何在CentOS 7.6操作系统上成功安装和配置Prometheus 2.17.1及Grafana 6.7.2-1,实现高效的数据监控与可视化。 ... [详细]
  • java文本编辑器,java文本编辑器设计思路
    java文本编辑器,java文本编辑器设计思路 ... [详细]
  • cJinja:C++编写的轻量级HTML模板引擎
    本文介绍了cJinja,这是一个用C++编写的轻量级HTML模板解析库。它利用ejson来处理模板中的数据替换(即上下文),其语法与Django Jinja非常相似,功能强大且易于学习。 ... [详细]
author-avatar
dghghjkk_952
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有