当前位置: 首页 > wzjs >正文

营销网站建设一薇上海做网站的小公司

营销网站建设一薇,上海做网站的小公司,留言网站建设的报告,网站301的作用文章目录 前言一、实现一个不能继承的类二、友元与继承三、继承与静态成员四、多继承以及菱形继承问题1.继承模型:2.菱形继承的问题3.虚拟继承解决数据冗余和二义性的原理4.虚拟继承的原理 五、继承的总结和反思1.继承和组合 总结 前言 各位好呀!今天呢我们接着讲继…

文章目录

  • 前言
  • 一、实现一个不能继承的类
  • 二、友元与继承
  • 三、继承与静态成员
  • 四、多继承以及菱形继承问题
    • 1.继承模型:
    • 2.菱形继承的问题
    • 3.虚拟继承解决数据冗余和二义性的原理
    • 4.虚拟继承的原理
  • 五、继承的总结和反思
    • 1.继承和组合
  • 总结


前言

各位好呀!今天呢我们接着讲继承的相关知识,之前给大家已经分享了继承一部分知识。那今天小编就来给继承收个尾吧。来看看继承的剩下的一部分。
在这里插入图片描述


一、实现一个不能继承的类

想要实现一个不能被继承的类的呢有两种方法:

  1. 方法一:父类的构造函数私有,子类的构造必须调用父类的构造函数,但是父类的构造函数私有化以后呢,在子类中是不可见也不可调用的。那么 子类就无法实例化出对象,这样就可以达到父类不能被继承(C++98的方法)。
  2. 方法二:C++11新增了一个关键字final,用final修饰父类,那么子类就无法继承父类了
#include<iostream>
#include<string>
using namespace std;
class Person//C++11
{
public:
protected:string _name; 
private:Person()//私有化构造函数{}
};
class student:public Person  
{
public:
private:string ID;
};
int main()
{student s;//这里会报错的,因为构造函数已经被私有化,子类是调不到父类的构造函数的//但是这里要注意的是:如果我们这里不定义,代码是不会报错的。return 0;
}#include<iostream>
#include<string>
using namespace std;
class Person final//C++11
{
public:Person()//私有化构造函数 {} 
protected:string _name; 
private:};
class student:public Person  //像这样用final修饰父类的话,父类也不能被子类继承 
{
public:
private:string ID;
};
int main()
{student s;return 0;
}

二、友元与继承

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

解决方法在子类中加上友元就可以了。还有就是要注意一下需要前置声明一下子类

#include<iostream>
#include<string>
using namespace std;
class student;  //前置声明
class Person
{friend void  Print(const Person& p, const student& s); //编译器在遇到一个变量和函数的时候,都只会向上查找(提高查找的效率),// 所以这里的student就会向上查找,但是上面没有student,student在下面//还有就是student不能放在方面取,因为student要继承Person。这两者相互依赖。//为了解决这个问题呢我们会在上面加一个前置声明
public:
protected:string _name="帅哥"; 
};
class student:public Person 
{friend void  Print(const Person& p, const student& s); //由于继承关系不能被继承下来,所以就访问不到student中_num成员变量//解决这个问只需要像这样,加一个友元就可以解决这个问题了。
public:
protected :string _num="123456";
};
void Print(const Person& p, const student& s)
{cout << p._name << endl;  cout << s._num << endl; 
}
int main()
{student v;Person  c;Print(c,v);    return 0;
}

三、继承与静态成员

#include<iostream>
#include<string>
using namespace std; 
class Person
{
public:string _name; static int n;       
}; 
int Person::n = 1; 
class student :public Person
{
public:string  _num;
};
int main()
{Person p;student s;//非静态成员变量的地址 cout << &p._name << endl;cout << &s._name << endl; cout << endl; //静态成员变量的地址cout << &p.n  << endl;cout << &s.n << endl; return 0;
}

在这里插入图片描述

我们通过看到非静态成员_name地址是不一样,这说明了子类继承下来的成员在子类和父类中各有一份。但是静态成员是不是地址相同呀?这又说明父类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例。
还有一个就是在共有的情况下,父类和子类指定作用域就可以访问静态成员。这里突破作用域就可以访问,因为它没有存在对象里面,而是存在静态区,它只是受到类域的限制而已。还有就可以把静态成员理解成全局的。

四、多继承以及菱形继承问题

1.继承模型:

继承模型呢分为三种:单继承,多继承和菱形继承

  1. 单继承一个子类只有一个直接父类时称这种继承关系为单继承
    在这里插入图片描述
  2. 多继承一个子类有两个或以上直接父类时称这个继承关系为多继承
    在这里插入图片描述
  3. 菱形继承菱形继承属于一个特殊的多继承

在这里插入图片描述

2.菱形继承的问题

菱形继承主要时两个问题,分别是 二义性和数据冗余

二义性
首先,什么是二义性?二义性就是在访问数据的时候发生歧义,不知道访问那个。

示例:

#include<iostream>
#include<string>
using namespace std; 
class A
{
public:string _name;int _age;
};
class B:public A 
{
public:
protected:string  _number;
};
class C :public A
{
public:
protected:string Gender;  
};
class D :public B, public C
{
public:
protected:string ID;
};
int main()
{D d;d._name;//存在二义性 
}

在这里插入图片描述
问题分析
这里为什么会存在访问不明确呢?结合之前的知识,子类继承父类成员,那么子类和父类中是不是都分别有一份独立的成员。但是现在B和C这两个类都继承了A,然而D又继承B和C。也就是说A,B,C,D中分别都有一份_name,现在要访问父类中的成员_name,但是这里的D是继承了两个类,两个类中都有_name ,所以这里编译器就不知道该访问那个类里面的_name这就是二义性。

解决方法:
怎样解决这个问题呢?其实很简单,只需要显示指定访问那个父类中_name就可以解决问题,但是不能解决数据冗余的问题

#include<iostream>
#include<string>
using namespace std; 
class A
{
public:string _name;int _age;
};
class B:public A 
{
public:
protected:string  _number;
};
class C :public A
{
public:
protected:string Gender;  
};
class D :public B, public C
{
public:
protected:string ID;
};
int main()
{D d;d.B::_name="张三";//指定要访问的父类d.C::_name = "小张"; //指定要访问的父类
}

数据冗余:
数据冗余可以理解成数据重复造成空间的浪费

示例:
菱形继承还有个特别烦的点就是他会让空间变大,一个它的父类在被几个类继承时,那它就有几份。比如下列代码中,A在B,C中各有一份。

#include<iostream>
#include<string>
using namespace std; 
class A
{
public:string _name; int _age; 
};
class B:public A 
{
public:
protected:string  _number;
};
class C :public A
{
public:
protected: string Gender;  
};
class D :public B, public C
{
public:
protected:string ID;
};
class F:public A,public B
{
public:};
int main()
{D d;F f;cout << sizeof(d) << endl;//菱形继承大小cout << sizeof(f) << endl;//多继承的大小
}

在这里插入图片描述
可以看出两者的空间大小相差的将近一倍了。所以,一般不建议创建菱形继承,因为这样有太多的问题,有时候还把握不住,建议不使用。

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

菱形继承一般不建议使用,但是如果非要使用,那该怎样解决二义性和数据冗余呢?这里就要引用一个新的关键字 virtual(虚拟继承)

那这个关键字该怎么用呢?该加在哪里呢?先看示例:

#include<iostream>
#include<string>
using namespace std;
class A
{
public:string _name;int _age;
};
class B :virtual public A
{
public:
protected:string  _number;
};
class C :virtual public A
{
public:
protected:string Gender;
};
class D :public B, public C
{
public:
protected:string ID;
};
int main()
{D d;d._name = "张三";return 0;
}

通过上面的代码可以看出:
virtual应该加在产生二义性和数据冗余继承的地方,现在A是不是产生了二义性和数据冗余 ,那virtual就加在B和C继承的哪里。这样就解决了二义性和数据冗余的问题,这点我们可以通过监视窗口可以看出。
在这里插入图片描述
从监视窗口展示的原因,这里虽然看起来是三份,但其实是一份。这样是不是就解决了数据冗余和二义性的问题啊。
注意:这里的virtual不能只加在B或者C,必须要同时加在B和C

在这里插入图片描述
大家看看这上图,图中的关系是不是菱形继承呢?其实 上图也时菱形继承哦,大家不要对形状太刻板了哦,认为菱形继承那他的形状就必须时菱形。形状不是菱形但是有二义性和数据冗余的产生那他就是菱形继承,

思考以及解决方法
那这里的virtual该加在哪里呢?BC?还是DC?其实正确是应该是加在BC,这里是不是A产生二义性和数据冗余,那就要加BC呀!那这里可以不可以在BCD都加上virtual呢?这里就好比一个人只需要两根拐棍,而你偏要给他三根是一样的性质。在D那里都没有产生二义性和数据冗余那就没必要加。
在这里插入图片描述
还有就是大家在写代码的时候遇到上图这种继承的时候都加上virtual,这种情况呢属于过度防范了。首先我们可以先看看B和C有没有被同一个类继承。如果没有,可以先不用加;如果有,那再加上virtual是不是也不迟啊?所以大家在写代码的时候不要过度的防范二义性和数据冗余。

4.虚拟继承的原理

#include<iostream>
#include<string>
using namespace std;
class A
{
public:A(const char*name,int age=18):_name(name),_age(age) {}string _name;int _age;
};
class B :virtual public A
{
public:B(const char*name,const char*number="1234567899"):A(name),_number(number) {}
protected:string  _number;
};
class C :virtual public A
{
public:C(const char* name, const char* gender="男"):A(name), Gender(gender) {}
protected:string Gender;
};
class D :public B, public C 
{
public:D(const char*name,const char*id="1263457"):B(name) ,C(name) //,A(naem)//这里必须显示调用,不然会报错,//还有就是这里初始化怎么多name,那到底以谁的为准呢?,ID(id) {}
protected:string ID;
};
int main()
{D d("张三"); return 0;
}

在这里插入图片描述
这里从我们之前学的知识来看这里代码的逻辑应该时没有 问题的呀。调用子类的构造函数先调用父类的默认构造函数嘛。但是这里说class A 不存在默认构造。那是怎么回事呢?这不得不就要看看虚拟继承的原理了。
在这里插入图片描述
在这里插入图片描述

相比于普通的多继承,虚拟继承呢是要把class A拿出来放在最底下的一个类中。他就不像普通多继承那样class A分别存在class B 和class C中。因为他要解决二义性和数据冗余。与此同时,这里还要引入一个虚基表和虚基表指针,复杂的很,所以小编这里就没有展示出来。小编这里主要是像让大家看看这两种继承的有什么不同。回到上面的问题:由于这里A不在B和C里面了,而是一个单独的父类,所以A也因该显示调用。

总结:不要轻易使用菱形继承和写出菱形继承的代码,多继承可以用

五、继承的总结和反思

1. 很多人说C++语法复杂,其实多继承就是一个体现。有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂所以一般不建议设计出多继承,一定不要设计出菱形继承。否则在复杂度及性能上都有问题。

  1. 多继承可以认为是C++的缺陷之一,很多后来的OO语言都没有多继承,如Java。

1.继承和组合

  1. public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。
  2. 组合是一种has-a的关系,。假设B组合了A,每个B对象中都有一个A对象。
    示例:我们以实现一个简单的栈来演示:
//stack和cin构成has-a的关系
#include<iostream>
#include<string>
#include<stdbool.h> 
using namespace std;
class stack
{
public :void push(const int& x){cin.push_back(x);}void pop(){cin.pop_back();}const int& top()const {return cin.back();}bool empty(){return cin.empty();}
private:  vector<int >  cin; 
};
int main()
{stack s;s.push(1);s.push(2);s.push(3);while (!s.empty()){cout << s.top() << " ";s.pop();}return 0;
}//stack和vector是is-a关系
#include<iostream>
#include<stdbool.h> 
#include<vector>
using namespace std;
class stack:public std::vector<int>  
{
public:void push(const int& x){vector<int> ::push_back(x);}void pop(){vector<int> ::pop_back();}const int& top()const{return vector<int> ::back();}bool empty(){return vector<int> ::empty(); }
};
int main()
{stack s; s.push(1); s.push(2);s.push(3); while (!s.empty()) {cout << s.top() << " "; s.pop();}return 0;
}
  1. 优先使用对象组合,而不是类继承 。
  2. 继承允许你根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称为白箱复用(white-box reuse)。术语“白箱”是相对可视性而言:在继承方式中,基类的内部细节对子类可见 。继承一定程度破坏了基类的封装,基类的改变,对派生类有很大的影响。派生类和基类间的依赖关系很强,耦合度高。
  3. 对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse),因为对象的内部细节是不可见的。对象只以“黑箱”的形式出现。组合类之间没有很强的依赖关系,耦合度低。优先使用对象组合有助于你保持每个类被封装
  4. 实际尽量多去用组合。组合的耦合度低,代码维护性好。不过继承也有用武之地的,有些关系就适合继承那就用继承,另外要实现多态,也必须要继承。类之间的关系可以用继承,可以用组合,就用组合。

总结

到这里继承的相关知识小编就基本分享完了咯,如果有什么疑问欢迎大家讨论。那今天就到这里吧。
在这里插入图片描述


文章转载自:

http://9fyyFwgS.mktms.cn
http://WCtZqEHF.mktms.cn
http://NWsetin0.mktms.cn
http://4SawnOC5.mktms.cn
http://Vom4TNxx.mktms.cn
http://8LflzuG8.mktms.cn
http://O7KNR5mr.mktms.cn
http://fKRdmvjl.mktms.cn
http://rR1tb9ED.mktms.cn
http://jTe1Fs3c.mktms.cn
http://1WDKFdWf.mktms.cn
http://HL5yS458.mktms.cn
http://OXUASVSG.mktms.cn
http://TcgJLva6.mktms.cn
http://hckRDO4w.mktms.cn
http://lVj24iQc.mktms.cn
http://xGTUef6E.mktms.cn
http://3cFv3St9.mktms.cn
http://0XfCw0yG.mktms.cn
http://lOUGfNkf.mktms.cn
http://h7fhlujD.mktms.cn
http://keDbVFwn.mktms.cn
http://GdnUZ9O1.mktms.cn
http://n0vqO7fb.mktms.cn
http://DQRd5V2l.mktms.cn
http://b2y1qO1I.mktms.cn
http://6Rdk3E2R.mktms.cn
http://EJJLTdfz.mktms.cn
http://YPHVwNrX.mktms.cn
http://XOeFemNd.mktms.cn
http://www.dtcms.com/wzjs/694209.html

相关文章:

  • 哪个网站可以做行程wordpress 打不开页面
  • 台州企业网站模板建站网站搭建dns有用吗
  • 企业网站的制作周期seo诊断报告示例
  • 加强国资集团网站建设微信抽奖小程序怎么做
  • 西安企业网站建设高新区广告推广软文案例
  • 建设校园门户网站方案wordpress小图标
  • 婚恋网站怎么做互联网外包公司
  • 广东网站建设公司报价表wordpress文章分类页面置顶
  • 做电影网站都需要什么手续dede怎么做网站
  • 凡科网站建设网站win10搭建wordpress
  • ps怎么做网站图片营销型网站搭建公司
  • 建设网站方法中国域名网站排名
  • wordpress站点一百数据卡不帝国cms免费模板
  • 开发手机网站用什么语言wordpress 翻页函数
  • 企业网站建立之前必须首先确定wordpress自建站上可以买卖
  • 网页设计入门与应用做搜狗手机网站优化软
  • 设计师网站上海软考中级哪个含金量高
  • 培训教育学校的网站建设方案能和实体彩票店和做的彩票网站
  • 马鞍山做网站wordpress调用随机文章
  • 网站搭建哪里找方便市场营销实务
  • 做一个网站成本是多少免费做链接的网站
  • 什么网站可以注册微信支付方式英文电商网站建设
  • 做网站排名公司推荐青浦专业网站建设
  • 怎么做视频网站赚钱吗安徽省同济建设集团网站
  • 十大网站app软件大连网站seo
  • 购物网站建设详细教程网盟推广合作
  • app和网站开发的成本oneindex wordpress
  • 昌邑营销型网站建设抖音代运营方案怎么写
  • 制作网站需要多少时间南京广告公司排行榜
  • 网站花瓣飘落的效果怎么做找施工方案上哪个网站