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

网站建设公司哪家专业关键词优化举例

网站建设公司哪家专业,关键词优化举例,企业站网站建设,自己能建网站吗概述 面向对象编程技术非常看重软件的可重用性#xff0c;在C中#xff0c;可重用性是通过继承机制来实现的。继承机制允许程序员在保持原有类的数据和功能的基础上进行扩展#xff0c;增加新的数据和功能#xff0c;从而构成一个新的类#xff0c;也称为派生类。原有类在C中可重用性是通过继承机制来实现的。继承机制允许程序员在保持原有类的数据和功能的基础上进行扩展增加新的数据和功能从而构成一个新的类也称为派生类。原有类一般称之为基类。派生类不仅拥有基类的成员还拥有自身新增加的成员。继承与派生是C的重要组成部分也是C的基础知识。掌握好了继承与派生就对面向对象编程技术有了更深刻的理解。关于继承与派生的入门知识这里就不赘述了下面将介绍继承与派生相关的一些知识要点。 访问权限 派生类从基类派生时有三种继承方式分别是公有继承、保护继承、私有继承分别对应关键字public、protected、private。 公有继承时基类中public成员和protected成员在派生类中的访问权限不变private成员在派生类中不可访问。 保护继承时基类中public成员和protected成员在派生类中的访问权限变为protectedprivate成员在派生类中不可访问。 私有继承时基类中public成员和protected成员在派生类中的访问权限都变为privateprivate成员在派生类中不可访问。 可通过下表更清晰地看到不同继承方式下基类成员在派生类中的访问权限。 基类public成员 基类protected成员 基类private成员 公有继承 public protected 不可访问 保护继承 protected protected 不可访问 私有继承 private private 不可访问 派生类能否改变基类成员在自身的访问权限呢答案是肯定的通过using关键字即可。参看下面的示例代码。 class CBase { public:CBase();int m_nData1;protected:int m_nData2;private:int m_nData3; };CBase::CBase() : m_nData1(6), m_nData2(88), m_nData3(999) {NULL; }class CDerived : public CBase { public:using CBase::m_nData2;protected:using CBase::m_nData1;using CBase::m_nData3; // 编译错误 };CDerived derived; printf(data1 is %d\n, derived.m_nData1); // 编译错误 printf(data2 is %d\n, derived.m_nData2); // 编译正常 可以看到通过using 基类::基类成员的方式可以修改基类成员在派生类中的访问权限。m_nData1原来为public修改后变为protected。m_nData2原来为protected修改后变为public。由于m_nData3在基类CBase中为private故在派生类中无法访问因此无法通过using CBase::m_nData3修改private成员的访问权限。 构造顺序 构造派生类的对象时会按照顺序依次调用以下函数。 1、所有基类的构造函数。注意是根据继承基类的顺序而不是派生类中初始化列表的顺序来调用的。 2、派生类所有成员变量的构造函数。注意是根据声明成员变量的顺序而不是初始化列表的顺序来调用的。 3、派生类的构造函数。 在派生类的初始化列表中如果没有显式调用基类和成员变量的构造函数则自动调用基类和成员变量默认的构造函数。另外销毁派生类对象时调用析构函数的顺序与上面的顺序正好相反。 可以通过下面的示例代码更好地理解构造顺序和析构顺序。 class CTemp1 { public:CTemp1(){printf(CTemp1 constructor\n);}~CTemp1(){printf(CTemp1 destructor\n);} };class CTemp2 { public:CTemp2(int nNumber){printf(CTemp2 constructor: %d\n, nNumber);}~CTemp2(){printf(CTemp2 destructor\n);} };class CTemp3 { public:CTemp3(){printf(CTemp3 constructor\n);}~CTemp3(){printf(CTemp3 destructor\n);} };class CBase1 { public:CBase1(){printf(CBase1 constructor\n);}~CBase1(){printf(CBase1 destructor\n);} };class CBase2 { public:CBase2(int nNumber){printf(CBase2 constructor: %d\n, nNumber);}~CBase2(){printf(CBase2 destructor\n);} };class CBase3 { public:CBase3(){printf(CBase3 constructor\n);}~CBase3(){printf(CBase3 destructor\n);} };class CDerived : public CBase1, public CBase2, public CBase3 { public:CDerived() : m_tmp2(66), m_tmp1(), CBase2(88), CBase1() {printf(CDerived constructor\n);}~CDerived(){printf(CDerived destructor\n);}private:CTemp1 m_tmp1;CTemp2 m_tmp2;CTemp3 m_tmp3; };CDerived derived; 上述示例的输出如下 CBase1 constructor CBase2 constructor: 88 CBase3 constructor CTemp1 constructor CTemp2 constructor: 66 CTemp3 constructor CDerived constructor CDerived destructor CTemp3 destructor CTemp2 destructor CTemp1 destructor CBase3 destructor CBase2 destructor CBase1 destructor 从输出可以得出以下几点。 1、在CDerived的初始化列表中先初始化了m_tmp2和m_tmp1但依然先调用了三个基类的构造函数。 2、在CDerived的初始化列表中先初始化了CBase2然后才初始化了CBase1但依然按照继承基类的顺序先调用了CBase1的构造函数。 3、在CDerived的初始化列表中没有初始化CBase3但依然调用了CBase3的默认构造函数。如果CBase3没有默认构造函数则编译出错。 4、在CDerived的初始化列表中先初始化了m_tmp2然后才初始化了m_tmp1但依然按照声明成员变量的顺序先调用了m_tmp1的构造函数。 5、在CDerived的初始化列表中没有初始化m_tmp3但依然调用了m_tmp3的默认构造函数。如果m_tmp3没有默认构造函数则编译出错。 6、析构的顺序与构造的顺序正好相反。 同名覆盖 派生类和基类可以拥有同名的成员此时派生类会把基类中所有同名的成员包括多个重载版本的函数都覆盖掉。要想调用基类的成员必须加作用域。 class CBase { public:CBase() : m_nData(66){NULL;}void ShowData(){printf(CBase data is %d\n, m_nData);}void ShowData(const std::string strData){printf(CBase data is %s\n, strData.c_str());}int m_nData; };class CDerived : public CBase { public:CDerived() : CBase(), m_nData(88){NULL;}void ShowData(){printf(CDerived data is %d, %d\n, m_nData, CBase::m_nData);}int m_nData; };CDerived derived; derived.ShowData(); derived.ShowData(CSDN); // 编译出错 printf(data is %d\n, derived.m_nData);derived.CBase::ShowData(); derived.CBase::ShowData(CSDN); printf(data is %d\n, derived.CBase::m_nData);CBase *pBase derived; pBase-ShowData(); 上述示例的输出如下 CDerived data is 88, 66 data is 88 CBase data is 66 CBase data is CSDN data is 66 CBase data is 66 可以看到调用派生类对象derived的成员函数ShowData()和成员变量m_nData时都是使用的派生类中的成员。调用派生类对象derived的ShowData(CSDN)时因为同名会覆盖基类中多个重载版本的函数导致基类中重载字符串参数的函数在派生类中被隐藏了不可见故会报编译错误。加上作用域后便可以指定访问基类中的成员变量和成员函数。另外将基类指针指向一个派生类对象时用基类指针调用的都是基类中的成员不涉及虚函数属于静态绑定。 多继承 多继承是指派生类同时从多个基类派生。如果多个基类中有同名的public和protected成员则会引起歧义导致编译出错。由于基类中的private成员在派生类中不可访问故同名的private成员不会引起问题。解决多基类同名的方法为使用作用域访问指定基类中的同名成员。可参看下面的示例代码。 class CBase1 { public:CBase1() : m_nNumber(66), m_strText(Hello), m_bPassed(true){NULL;}int m_nNumber;protected:std::string m_strText;private:bool m_bPassed; };class CBase2 { public:CBase2() : m_nNumber(88), m_strText(CSDN), m_bPassed(false){NULL;}int m_nNumber;protected:std::string m_strText;private:bool m_bPassed; };class CDerived : public CBase1, public CBase2 { public:void Show(){// 编译出错printf(data is %d, %s\n, m_nNumber, m_strText.c_str());// 输出CBase1 data is 66, Helloprintf(CBase1 data is %d, %s\n, CBase1::m_nNumber, CBase1::m_strText.c_str());// 输出CBase2 data is 88, CSDNprintf(CBase2 data is %d, %s\n, CBase2::m_nNumber, CBase2::m_strText.c_str());} }; 可以看到由于CBase1和CBase2中均有m_nNumber和m_strText在CDerived中直接访问这两个成员会引发编译错误。通过指定作用域CBase1::和CBase2::可以在派生类中指定访问CBase1和CBase2的成员。 虚函数 虚函数在C中主要是为了实现多态机制。所谓多态也就是用基类的指针指向派生类的实例然后通过基类的指针调用派生类实例的成员函数。可参看下面的示例代码。 class CBase { public:CBase() : m_nData1(66){NULL;}virtual void Test1(){printf(CBase Test1\n);}virtual void Test2(){printf(CBase Test2\n);}virtual void Test3(){printf(CBase Test3\n);}private:int m_nData1; };class CDerived : public CBase { public:CDerived() : CBase(), m_nData2(88){NULL;}virtual void Test1(){printf(CDerived Test1\n);}virtual void Test2(){printf(CDerived Test2\n);}private:int m_nData2; };CBase *pBase new CDerived(); pBase-Test1(); // 输出CDerived Test1 pBase-Test2(); // 输出CDerived Test2 可以看到通过基类指针pBase调用虚函数Test1和Test2时调用的是派生类中的函数。 那么虚函数是如何实现的呢 在C中具有虚函数的类都有一张虚函数表。这个表相当于一个一维数组用于存储类中所有虚函数的地址。编译器必须保证对象实例最开始的位置存放指向虚函数表的指针然后才能存放其他成员。可通过下面的示例代码来理解虚函数表的概念。 typedef void (*Test)();CBase base; Test pTest1 (Test)*((size_t *)*(size_t *)(base)); pTest1(); Test pTest2 (Test)*((size_t *)*(size_t *)(base) 1); pTest2(); int nData (int)*((size_t *)(base) 1); printf(data is %d\n, nData);CDerived derived; pTest1 (Test)*((size_t *)*(size_t *)(derived)); pTest1(); pTest2 (Test)*((size_t *)*(size_t *)(derived) 1); pTest2(); Test pTest3 (Test)*((size_t *)*(size_t *)(derived) 2); pTest3(); int nData1 (int)*((size_t *)(derived) 1); int nData2 (int)*((size_t *)(derived) 2); printf(data is %d, %d\n, nData1, nData2); 上述示例的输出如下 CBase Test1 CBase Test2 data is 66 CDerived Test1 CDerived Test2 CBase Test3 data is 66, 88 可以看到我们完全通过指针的操作就访问了类实例中的虚函数和成员变量。在上面的代码中(size_t *)(base)为指向虚函数表的指针*(size_t *)(base)为虚函数表的地址相当于一维数组的地址(size_t *)*(size_t *)(base)指向虚函数表中第一个虚函数的地址*((size_t *)*(size_t *)(base))则是第一个虚函数。其他虚函数和成员变量的指针转换与此类似这里不再赘述。下图给出了类实例base和derived的内存布局结构供大家参考。 上面讨论的都是单继承的情况多继承时原理类似只是更复杂些这里就不再深入介绍了。 虚继承 虚继承是为了解决菱形继承中存在多份公共基类的拷贝从而导致二义性的问题。在定义派生类时如果在基类的名字前面加上virtual关键字则构成虚继承。先通过下面的示例代码来看看菱形继承的问题。 class CBase { public:CBase() : m_nNumber(1){printf(CBase default constructor\n);}CBase(int nNumber) : m_nNumber(nNumber){printf(CBase constructor: %d\n, nNumber);}protected:int m_nNumber; };class CDerived1 : public CBase { public:CDerived1() : CBase(66){printf(CDerived1 constructor\n);} };class CDerived2 : public CBase { public:CDerived2() : CBase(88){printf(CDerived2 constructor\n);} };class CFinal : public CDerived1, public CDerived2 { public:CFinal() : CDerived1(), CDerived2(){printf(CFinal constructor\n);}void Show(){printf(CFinal show: %d\n, m_nNumber); // 编译出错printf(CFinal show 1: %d\n, CDerived1::m_nNumber);printf(CFinal show 2: %d\n, CDerived2::m_nNumber);} };CFinal final; final.Show(); 上述示例的输出如下 CBase constructor: 66 CDerived1 constructor CBase constructor: 88 CDerived2 constructor CFinal constructor CFinal show 1: 66 CFinal show 2: 88 可以看到CFinal继承了CDerived1和CDerived2而CDerived1和CDerived2都继承了CBase。在CFinal中直接访问公共基类CBase中的成员变量m_nNumber时便会存在二义性问题。虽然可以通过指定作用域来分别访问CDerived1和CDerived2中的m_nNumber但CBase存在多份的问题仍然存在调用了两次CBase的构造函数。 再来看看使用虚继承时的示例代码。 class CBase { public:CBase() : m_nNumber(1){printf(CBase default constructor\n);}CBase(int nNumber) : m_nNumber(nNumber){printf(CBase constructor: %d\n, nNumber);}protected:int m_nNumber; };class CDerived1 : public virtual CBase { public:CDerived1() : CBase(66){printf(CDerived1 constructor\n);} };class CDerived2 : public virtual CBase { public:CDerived2() : CBase(88){printf(CDerived2 constructor\n);} };class CFinal : public CDerived1, public CDerived2 { public:CFinal() : CDerived1(), CDerived2(){printf(CFinal constructor\n);}void Show(){printf(CFinal show: %d\n, m_nNumber); // 编译正常printf(CFinal show 1: %d\n, CDerived1::m_nNumber);printf(CFinal show 2: %d\n, CDerived2::m_nNumber);} };CFinal final; final.Show(); 上述示例的输出如下 CBase default constructor CDerived1 constructor CDerived2 constructor CFinal constructor CFinal show: 1 CFinal show 1: 1 CFinal show 2: 1 可以看到使用虚继承后公共基类CBase的构造函数只调用了一次且调用的是默认构造函数。这是因为虚基类的构造函数比较特殊与常规的构造函数有所不同。由于从虚基类派生出来的每一个派生类中其构造函数都调用了基类的构造函数这样编译器就无法确定到底用哪一个派生类来构造基类对象。最终编译器会忽略所有派生类中对基类构造函数的调用而选择调用基类的默认构造函数。 如果基类的默认构造函数不存在则编译器将报错。解决该问题的方法是显式在CFinal中调用CBase的其他构造函数。示例代码如下 class CFinal : public CDerived1, public CDerived2 { public:CFinal() : CDerived1(), CDerived2(), CBase(2){printf(CFinal constructor\n);}void Show(){printf(CFinal show: %d\n, m_nNumber);printf(CFinal show 1: %d\n, CDerived1::m_nNumber);printf(CFinal show 2: %d\n, CDerived2::m_nNumber);} };
http://www.dnsts.com.cn/news/37130.html

相关文章:

  • 昆明微信网站建设wordpress设置多域名多站点
  • 做网站赚钱全攻略平面设计发展前景
  • 甘肃省临夏州建设局网站工作室装修
  • 外贸网站做哪些语言浙江省住房和城乡建设行业网站
  • 湛江论坛建站模板销售管理系统哪种好一点
  • 哈尔滨模板建站定制网站产品网站建设方案
  • 做慕课的网站dw网页制作模板下载
  • 做网站费免图片网站seo店铺描述
  • 企业营销网站建设系统比较多人用什么网站做推广
  • 网站备案所需资料去哪里弄Wordpress
  • 手机网站注册深圳工程建设交易中心网
  • 西安网站建设制作专业公司宣城网站建设
  • 河南企业网站定制企业管理10大系统
  • 网站设计遵循的原则上海技术做网站
  • 网站调用谷歌地图有赞微商城怎么收费
  • 安全认证的机票网站成就怎么做互联网公司设计
  • 接做名片的网站建立soho公司网站
  • 销售的产品是帮别人做网站网站显示正在建设中
  • 插画师培训网站建设程序员培训机构有哪些
  • 快设计网站官网互联网高端官网
  • 支付集成文件放在网站哪里wordpress安装服务器
  • 做视频有赚钱的网站有哪些深圳软件开发培训机构
  • Asp.net网站开发分析amp 网站开发
  • 重庆微信网站代理商广州公司网站制作
  • 站酷设计网站怎样下载图片一个网页大概多少钱
  • 网站关键词几个最好大众的网站建设
  • 网站建设与维护考试卷门户网站开发专业
  • 聊城建网站哪家好免费wordpress申请
  • 东莞企业网站模板建站安康seo
  • js做示爱网站例子网页设计怎么把图片上移