0
点赞
收藏
分享

微信扫一扫

SpringBoot篇---第三篇

前言

在很多程序中都存在着一些互相关联但是有细微差别的概念,比如,同一家服装店,不同衣服价格的定价策略不同,比如有的原价销售,有的打折销售。有时当总价格达到某个量级就会经行减免。

这时面向对象编程(OOP)适用于这类应用。

一、面向对象编程

这个概念太过宏大而且每个人都有自己对于其的了解,这里我们就简单讲讲什么是面向对象编程。

二、继承的概念及定义

2.1继承的概念

 通过继承联系在一起的类构成一种层状结构,通常在层状结构的根部有一个基类,其他类直接或间接从基类继承而来,这些继承得到的类称为派生类。基类负责定义在层次关系中所有类共同拥有的成员,而每个派生类定义各自特有的成员。

2.2继承定义

定义格式

 继承关系和访用限定符

继承基类成员访问方式的变化

总结:

三、派生类对象及派生类向基类的的类型转换

一个派生类对象包含多个组成部分:一个含有派生类自己定义的(非静态)成员的子对象,以及一个与该派生类继承的基类对应的子对象,如果有多个基类,那么这样的子类对象也有多个。

如上图所定义的student对象,它拥有一个自己定义的学号_No编号,还有继承自Person三个成员变量。(注:c++标准没有明确规范派生类对象在内存中如何分配,但是我们可以认为是如图分配的,在一个对象中,继承自基类的部分和派生类自定义的部分不一定是连续存储的)。

对于基类对象和派生类对象来说

class Person
{
protected :
 string _name; // 姓名
    string _sex;  // 性别
    int _age; // 年龄
};
class Student : public Person
{
public :
 int _No ; // 学号
};
void Test ()
{
 Student sobj ;
 // 1.子类对象可以赋值给父类对象/指针/引用
 Person pobj = sobj ;
 Person* pp = &sobj;
 Person& rp = sobj;
    
 //2.基类对象不能赋值给派生类对象
    sobj = pobj;
    
    // 3.基类的指针可以通过强制类型转换赋值给派生类的指针
    pp = &sobj
    Student* ps1 = (Student*)pp; // 这种情况转换时可以的。
    ps1->_No = 10;
    
    pp = &pobj;
 Student* ps2 = (Student*)pp; // 这种情况转换时虽然可以,但是会存在越界访问的问
题
    ps2->_No = 10;
}

四、继承中的作用域

要注意的是第三条,如果基类和派生类有函数名相同但参数不同,不会构成函数重载,也派生类对象也无法调用基类中的函数,如下:

class A
{
public:
	
	void fun(int c)
	{
		cout << "A";
	}
	int a;

};
class B :public A
{
public:
	void fun(int c,int d)
	{
		cout << "B";
	}
};

int main()
{
	B b;
	int a=0;
	b.fun(a);
}

会显示b.fun()调用参数太少。

五、派生类的默认成员函数

六、继承与友元,静态成员

友元关系不能被继承,也就是说基类友元不能访问子类私有和保护成员。

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子

类,都只有一个static成员实例 。

七、继承与组合

继承和组合

 八、多继承,复杂的菱形继承和虚拟继承

单继承:一个子类只有一个直接父类时称这个继承关系为单继承

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承

菱形继承:菱形继承是多继承的一种特殊情况。

 会顾之前第三章中的派生类对象拥有的内容,我们很容易发现问题,那就是最下方的Assistant类在实例化时会在内存中存两个Person的类成员。

那问题来了当我们从Assistant类中访问_name时,我们到底该访问哪个地址的数据,如果我们让该对象去直接转换成Student, Teacher的对象时,我们该在进行“切片”时,数据又该如何分配。

这就是数据二义性和数据冗余问题。

// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
 a.Student::_name = "xxx";
 a.Teacher::_name = "yyy";

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在Student和

Teacher的继承Person时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地

方去使用。

8.1虚拟继承解决数据冗余和二义性的原理

这里我们为了研究虚拟继承原理,创建一个简单的菱形虚拟继承体系,再借助内存窗口观察对象成员的模型。

class A
{
public:
    int _a;
};
class B : virtual public A
{
public:
     int _b;
};
class C : virtual public A
{
public:
     int _c;
};
class D : public B, public C
{
public:
     int _d;
};
int main()
{
 D d;
 d.B::_a = 1;
 d.C::_a = 2;
 d._b = 3;
 d._c = 4;
 d._d = 5;
 return 0;
}

下图是菱形继承的内存对象成员模型:这里可以看到数据冗余(没有加virtual)

 

下图是菱形虚拟继承的内存对象成员模型:这里可以分析出D对象中将A放到的了对象组成的最下

面,这个A同时属于B和C,那么B和C如何去找到公共的A呢?这里是通过了B和C的两个指针,指

向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量

可以找到下面的A

 也就是说当我们在访问_a时会直接访问到一个偏移量,根据这个偏移量我们可以找到D中所存的独一份的A。

8.2总结

举报

相关推荐

maven篇---第三篇

MySQL篇---第三篇

第三篇:继承

openCV第三篇

寒假第三篇

【Linux】第三篇:进程

python学习第三篇

java基础-----第三篇

0 条评论