虚基类

C++对象模型:单继承,多继承,虚继承

泄露秘密 提交于 2019-12-24 14:13:08
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 什么是对象模型 有两个概念可以解释C++对象模型: 语言中直接支持面向对象程序设计的部分。 对于各种支持的底层实现机制。 类中成员分类 数据成员分为静态和非静态,成员函数有静态非静态以及虚函数 class data members:static和nonstatic class data functions:static、nonstatic和virtual 比如: class Base { public: Base(int i) :baseI(i){}; int getI(){ return baseI; } static void countI(){}; virtual void print(void){ cout << "Base::print()"; } virtual ~Base(){} private: int baseI; static int baseS; }; 对象模型分类 简单对象模型 :这个模型非常地简单粗暴。在该模型下,对象由一系列的指针组成,每一个指针都指向一个数据成员或成员函数,也即是说,每个数据成员和成员函数在类中所占的大小是相同的,都为一个指针的大小。这样有个好处——很容易算出对象的大小,不过赔上的是空间和执行期效率。所以这种对象模型并没有被用于实际产品上。 表格驱动对象模型

重拾C++之虚函数和虚基类以及抽象类

霸气de小男生 提交于 2019-12-24 14:09:47
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 一、引言 好久没接触过C++了,今天突然要用一点感觉号蛋疼,用惯了python感觉C++一点都不会了。 声明了一个类的对象居然用这种方法,脑子绝对是被驴(python)踢了 class A{ ... } a=A();//尼玛这都能行,被踢大了 二、虚函数和一般函数 虚函数就是加了vritual关键字的函数,引入虚函数的目的是为了实现多态性(在此为运行时的多态性),即可以通过父类的指针调用子类的对象,从而产生不同的效果。 virtual void show(){ cout<<"hello my name is a"<<endl; } 废话不多说,为了展示虚函数和一般函数的区别看看下面一个个例子: #include<iostream> using namespace std; class A{ private: int a; int b; public: A(int a,int b){ this->a=a; this->b=b; cout<<"hello base A"<<endl; cout<<a<<'-'<<b<<endl; } //定义一个虚函数 virtual void show(){ cout<<"hello my name is a"<<endl; } }; class D:public A{

【选择恐惧症】接口?虚基类?

北城以北 提交于 2019-12-21 10:50:23
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 症前兆 记得有个朋友跟我讨论过这样的一个问题,说到他刚刚学习 接口 和 虚基类 的相关知识时觉得很迷茫,不知道什么时候该用接口,什么时候该使用虚基类。后来慢慢地发现接口能做的事情,虚基类也能够实现,甚至有更多的特点。再后来就慢慢地放弃了接口,把所有的设计和实现都采用虚基类来替代。不能说我这个朋友这样的处理有错,但是就我个人对接口和虚基类的理解来说,这样的做法是有不妥的地方。 症分析 所谓的 接口 简单的来说就是个“门口”,而这个"门口"是安装在某个模块或者服务上,其目的就是为了让外面的世界通过这个“门口”可以访问到模块上的功能或服务。由于是跟外部环境做对接,因此给它定义为-- 接口 。而 虚基类 则更像一间毛胚房,整个架子已经有了(包括门口),想要什么东西就直接往里面放,但是摆放的东西跟整个架子的设计有关,不是所有的东西都能乱摆,就好像原本规划为洗手间的空间,总不能把床摆在里面吧(当然,你乐意也是可以的。)。 症解答 说到这里,其实已经能够感觉到它们的区别是什么了,表面上 虚基类 感觉更加强大一点,可以像 接口 那样声明一系列的方法(这里的方法是没有实现体的,在 虚基类 中我们把这类方法叫“虚方法”),又能定义一些共有的属性;但是,因为 虚基类 也是一个类型,是必须要继承与它才能够拥有这样的一些特性

3.继承与派生

只愿长相守 提交于 2019-12-18 15:18:19
1.类的继承与派生   - 类的继承:从已有类产生新类的过程。原有类称为基类或父类,产生的新类称为派生类或子类。   - 派生类语法:       class 派生类名:继承方式 基类名1,继承方式  基类名2,...     {     }   - 单继承和多继承:基类个数决定   - 直接基类,间接基类   - 继承方式规定了如何访问从基类继承的成员   - 派生类成员是指除了从基类继承的所有成员之外,新增加的数据和函数成员   - 派生类生成过程:吸收基类成员->改造基类成员->添加新的成员,构造函数和析构函数都不被继承 2.访问控制   - public:继承后,基类数据为public   - protected:继承后,基类数据为protected   - private:继承后,基类数据为private 3.类型兼容性规则:指在需要基类的任何地方,都可以使用公有派生类的对象来代替(公有继承)   - 代替包含以下情况     * 派生类的对象可以隐含转换为基类对象     * 派生类对象可以初始化基类的引用     * 派生类的指针可以隐含转换为基类指针   - 在代替之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员 4.派生类的构造和析构函数   - 构造函数:     派生类构造函数执行的一般次序     * 调用基类构造函数

c++的构造函数调用顺序

▼魔方 西西 提交于 2019-12-17 21:07:14
c++构造函数调用顺序 c++因为有着复杂的类间继承与派生的关系,构造函数的调用关系也很复杂 1.若同一层次中同时包含虚基类和非虚基类类,先调用虚基类的构造函数,再调用非虚基类的构造函数。 2.在虚基类中定义有带参数的构造函数,并且没有定义默认形式的构造函数,则整个继承结构中,所有直接或间接的派生类都要在构造函数的成员初始化列表中列出对虚基类构造函数的调用。 代码: #include<iostream> using namespace std; class B1{ public: int n1; B1(int in_n1) { n1=in_n1; cout<<"B1.n1="<<n1<<endl;} }; class B21: virtual public B1{ public: int n21; B21(int a):B1(a) { n21=a; cout<<"B21.n21="<<n21<<endl; } }; class B22:virtual public B1{ public: int n22; B22(int a):B1(a){ n22=a; cout<<"B22.n22="<<n22<<endl; } }; class B3:public B21,public B22{ public: int n3; B3(int a):B21(a),B22(a),B1(a){ n3

C++ 多重继承(环状继承)

不羁岁月 提交于 2019-12-15 07:10:09
虚基类解决二义性模糊性问题 ambigous 二义性、模糊性 继承定义虚基类 (子类继承父类的时候,在父类前加 virtual) # include <iostream> using namespace std ; //基类 class Beauty { public : string name ; double height ; protected : int age ; private : double weight ; // public : Beauty ( ) { } Beauty ( string n , int a , double h , double w ) { name = n ; age = a ; height = h ; weight = w ; } void setinfo ( string n , int a , double h , double w ) { name = n ; age = a ; height = h ; weight = w ; } double get_weight ( ) { return weight ; } void show ( ) { cout << name << " " << age << " " << height << " " << weight << endl << endl ; } ~ Beauty (

C++中的 虚函数 纯虚函数 虚基类(virtual)

China☆狼群 提交于 2019-12-11 10:34:55
前言 :需要了解三者的区别,必须要掌握多态的三个必要条件: 继承 重载 父类指针指向子类对象。 虚函数 纯虚函数 虚基类三者区别 1.虚函数是用于多态中virtual修饰父类函数,确保父类指针调用子类对象时,运行子类函数的。 2.纯虚函数是用来定义接口的,也就是基类中定义一个纯虚函数,基类不用实现,让子类来实现。 3.虚基类是用来在多继承中,比如菱形继承中,如果两个父类继承自同一个类,就只实例化一个父类 ①虚函数 第一个是没有使用多态(只用继承)的一般实现方式: class A { public: void printf(){ cout<<"printf A"<<endl; } }; class B : public A { public: void printf(){ cout<<"printf B"<<endl; } }; int main(int argc, const char * argv[]) { A *a = new A(); a->printf(); B *b = new B(); b->printf(); return 0; } 结果: printf A printf B 这是早期没有多态的代码,缺点:代码冗余 下面是使用了多态但是没有引用virtual关键字的情况: int main(int argc, const char * argv[]) { A *a =

C++面向对象程序设计学习笔记(5)

…衆ロ難τιáo~ 提交于 2019-12-07 09:14:27
派生类与继承 概念 继承允许编程者在已有类的基础上创建新的类,可以从一个或者多个已有类中继承函数和数据,并重新定义或者添加新的函数和数据,已有类称为基类或父类,新类称为派生类和子类。 声明 声明一个派生类的一般格式为: class 派生类名 : [继承方式] 基类名 { 派生类新增的数据成员和成员函数 }; 继承方式种类有 private, public ,protected ,分别为私有、公有和保护继承 若不显式地给出关键字,则默认为私有 构成 构造一个派生类包括三部分公作: 1)派生类从基类接受成员 派生类将基类除构造函数和析构函数以外的全部成员全部接收 2)调整从基类接收来的成员 调整包括两个方面 改变基类成员在派生类中的访问属性(通过继承方式实现) 对基类成员重定义(派生类的同名成员会覆盖基类中的同名成员) 3)在派生类中添加新的成员 基类成员在派生类中的访问属性 基类中的成员 在公有派生类中的访问属性 在私有派生类中的访问属性 在保护派生类中的访问属性 私有成员 不可直接访问 不可直接访问 不可直接访问 公有成员 公有 私有 保护 保护成员 保护 私有 保护 派生类对基类成员的访问规则 派生类对基类成员的访问形式主要有两种: (1)内部访问 由派生类中新增的成员函数对基类继承来的成员的访问 (2)对象访问 在派生类外部,通过派生类对象对从基类继承来的成员的访问

什么情况下应用纯虚类

天大地大妈咪最大 提交于 2019-12-07 07:01:43
前几天跟同事brainstorm,讨论一个关于纯虚类的使用问题,挺有意思。回来心中久久不能平静,写出来一吐为快。 不论在C++中还是C#中,纯虚类都是不能实例化的,这是因为纯虚类其实是一个对业务类型的一种高度抽象,本质上是不存在这种东西的,所以也就不能实例化它。对于C++中只要类中含有一个纯虚函数就是纯虚类,而C#中是abstract修饰的类就是纯虚类,即使类中没有虚方法也可以是纯虚类,在这里我觉得C#的纯虚类没有C++的严谨,如果纯虚类中没有纯虚方法的话,那有何意义。 明白了纯虚类的原理,那纯虚类应该肯定需要被别的类继承的,因为如果不继承的话,它自己本身也不能实例化,就没有存在的意义了,所以它肯定是需要被继承的。那它需不需要含有一个或者多个纯虚方法呢?答案是肯定的,因为既然纯虚类是需要被继承的,那没有纯虚方法又有何意义。没有纯虚方法它就应该是可以实例化的,那就没有必要将其设定为纯虚类的,这也是我吐槽C#的abstract的一个原因。 有了纯虚类一定要有纯虚方法的这个基础,那就可以想象纯虚类的业务场景应该是下面这个样子的 abstract class Goods { public int GetPrice() { int price = 0; //do some standard things price = this.CaculatePrice(); //do some

多态性总结

青春壹個敷衍的年華 提交于 2019-12-02 12:47:41
  多态从实现的角度可以划分为:编译时多态和运行时的多态。 运算符重载   运算符重载即静态多态,是对已有的运算符赋予多重含义,运算符重载是通过创建运算符函数实现的,运算符函数定义了重载的运算符将要进行的操作。运算符函数的定义与其他函数的定义类似,唯一的区别是运算符函数的函数名是由关键字 operator 和其后要重载的运算符符号构成的。把指定的运算表达式转化为对运算符函数的调用,运用对象转化为运算符函数的实参。 • 运算符重载格式 函数类型 operator运算符 (形参){ …… } • 运算符重载规则 当重载为类的成员函数的情况,形式参数个数=原操作数个数-1(后置++、--除外)。 当重载为类友元函数的情况,形式参数个数=原操作数个数。 除了类属关系运算符 "." 、成员指针运算符 ".*" 、作用域运算符 "::" 、sizeof 运算符和三目运算符 "?:" 以外,C++ 中的所有运算符都可以重载。 重载运算符限制在 C++ 语言中已有的运算符范围内的允许重载的运算符之中,不能创建新的运算符。 //复数类成员函数自增 #include<iostream> using namespace std; class complex{ private: int real,imag; public: complex(int r,int i){ real=r; imag=i; }