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

上海物流网站建设博客网站

上海物流网站建设,博客网站,网站上飘窗怎么做,网站推广合同目录 一、继承概念与定义 1.1、什么是继承? 1.2、继承定义 二、继承关系与访问限定符 2.1、继承方式 三、基类与派生类对象的赋值转换 3.1、向上转型 3.2、对象切片 四、继承中的作用域 4.1、隐藏 五、派生类中的成员函数 5.1、构造与析构 六、继承与友…

目录

一、继承概念与定义

1.1、什么是继承?

1.2、继承定义

二、继承关系与访问限定符

2.1、继承方式

三、基类与派生类对象的赋值转换

3.1、向上转型

3.2、对象切片

四、继承中的作用域

4.1、隐藏

五、派生类中的成员函数

5.1、构造与析构

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

6.1、友元关系不可继承

6.2、静态成员共享

七、复杂的菱形继承与虚拟继承

7.1、菱形继承问题

7.2、虚拟继承

7.2.1、解决原理

八、继承与组合:如何选择?

1. 继承("is-a"关系)

2. 组合("has-a"关系)

3. 选择原则


一、继承概念与定义

1.1、什么是继承?

简单来说:继承就像现实中的父子关系。孩子继承父母的特征(如眼睛),但孩子也可以有自己的独特属性(如头发)。

而在代码中,继承是子类继承父类的字段和方法,同时可以添加新功能或覆盖父类的方法。

继承是面向对象编程中的一个核心机制,它允许一个类(子类/派生类)基于另一个类(父类/基类)来定义,从而自动获取父类的属性和方法,并可以在此基础上进行扩展或修改。

继承优势?

避免重复编写相同的代码。父类的通用逻辑只需要写一次,子类可以直接继承。减少了代码量。

比如:

class Person
{
public:void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}
protected:string _name = "peter"; // 姓名int _age = 18;  // 年龄
};class Student : public Person
{
protected:int _stuid; // 学号
};class Teacher : public Person
{
protected:int _jobid; // 工号
};int main()
{Student s;Teacher t;s.Print();t.Print();return 0;
}

上面代码可以看出对于“老师”和“学生”来说都具有“人”的属性,所以这里Student和Teacher都继承了Person这个类,继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。可以通过调试窗口看出来:

1.2、继承定义

Person是父类,也称作基类。Student是子类,也称作派生类。


二、继承关系与访问限定符

2.1、继承方式

C++支持三种继承方式:public、protected、private,它们决定了基类成员在派生类中的可见性:

基类成员访问权限public继承                        protected继承private继承
基类的public成员派生类的public成员派生类的protected 成员派生类的private 成员
基类的protected 成员派生类的protected 成员派生类的protected 成员派生类的private 成员
基类的private成 员在派生类中不可见在派生类中不可见在派生类中不可见

1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它

比如:

class Base 
{
public:int a;
protected:int b;
private:int c;
};class Derived : private Base 
{ // a → private, b → private, c不可见(就是不能访问父类的成员)
};

2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。

3. 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强。 


三、基类与派生类对象的赋值转换

3.1、向上转型

派生类对象可以直接赋值给基类的对象、基类指针或引用。基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的。

int main()
{Student sobj ;Person pobj = sobj; // 合法Person* pp = &sobj; // 合法Person& rp = sobj; // 合法sobj = pobj;//非法// 3.基类的指针可以通过强制类型转换赋值给派生类的指针pp = &sobjStudent* ps1 = (Student*)pp; // 这种情况转换时可以的。ps1->_No = 10;pp = &pobj;Student* ps2 = (Student*)pp; // 这种情况转换时虽然可以,但是会存在越界访问的问题ps2->_No = 10;return 0;
}

3.2、对象切片

向上转型有个形象的说法叫切片或者切割。寓意把派生类中父类那部分切来赋值过去。

当派生类对象直接赋值给基类对象时,会发生“切片”——派生类独有的成员被丢弃:


四、继承中的作用域

4.1、隐藏

子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏, 也叫重定义。(在子类成员函数中,可以使用 基类::基类成员 显示访问)

比如:


五、派生类中的成员函数

5.1、构造与析构

1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。

2. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。如下:

可以看到:派生类对象初始化先调用基类构造再调派生类构造。派生类对象析构清理先调用派生类析构再调基类的析构

注意:虽然这里的子类和父类析构名不同,也没加virtual,看起来不构成隐藏。实际上由于多态的原因析构函数的函数名被特殊处理了,统一处理成destructor。

另外:

3. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。

4. 派生类的operator=必须要调用基类的operator=完成基类的复制。


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

6.1、友元关系不可继承

基类的友元函数/类不会自动成为派生类的友元。

class Base 
{friend void friendFunc();
};class Derived : public Base 
{// friendFunc() 不是Derived的友元!
};

6.2、静态成员共享

基类的静态成员在整个继承体系中共享。

class Base 
{
public:static int count;
};class Derived : public Base {};int Base::count = 0;// 无论通过Base还是Derived访问,count都是同一个
Base::count++;
Derived::count++; 

七、复杂的菱形继承与虚拟继承

7.1、菱形继承问题

当派生类继承自两个具有共同基类的类时,会导致数据冗余和二义性:在Assistant的对象中Person成员会有两份。

class Person
{
public :string _name ; // 姓名
};class Student : public Person{};class Teacher : public Person{};class Assistant : public Student, public Teacher
{
protected :string _majorCourse ; // 主修课程
};void Test ()
{Assistant a ;// 这样会有二义性无法明确知道访问的是哪一个a._name = "peter"; // 这里的_name指的是Student里的还是Teacher里的?
}

7.2、虚拟继承

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。

class Person
{
public:string _name; // 姓名
};class Student : virtual public Person {};class Teacher : virtual public Person {};class Assistant : public Student, public Teacher
{
protected:string _majorCourse; // 主修课程
};void Test()
{Assistant a;a._name = "peter"; //指向唯一的_name
}

7.2.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;
}

图上用的32位系统展示,所以指针大小4个字节。

原理:通过虚拟继承,D对象仅包含一份A实例,B和C共享这一份。这里是通过了B和C的两个指针,指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A。


八、继承与组合:如何选择?

public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。

组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象

1. 继承("is-a"关系)

  • 适用场景:派生类是基类的特殊类型(如 Dog 是 Animal)。

  • 优点:代码复用、多态支持。

  • 缺点:可能导致紧耦合。

2. 组合("has-a"关系)

  • 适用场景:类包含另一个类的功能(如 Car 有一个 Engine)。

  • 优点:降低耦合、灵活替换组件

class Engine 
{
public:void start() { /* ... */ }
};class Car 
{
private:Engine engine;  // 组合
public:void start() { engine.start(); }
};

3. 选择原则

  • 优先使用组合:除非需要多态或严格的“is-a”关系。

  • 避免过度继承:继承层次过深会增加复杂度。

http://www.dtcms.com/wzjs/442737.html

相关文章:

  • 苹果软件做ppt模板下载网站有哪些网络推广竞价
  • 做农产品网站需要办什么证营销方案怎么写?
  • 杭州的网站建设公司哪家好互联网营销平台有哪些
  • googleseo优化班级优化大师免费下载
  • 炒股网站开发网站建设开发外包公司
  • 重庆网站建设 狐灵泉州全网营销优化
  • 做网站不签合同湖南企业网站建设
  • 网络营销导向网站建设的基础是什么免费com域名注册永久
  • wordpress外贸 模板宁波最好的seo外包
  • 手机访问自动跳转到wap网站的代码关键词林俊杰歌词
  • 二手房交易税费郑州网络seo公司
  • wordpress用户后台登录界面模板沧州网站优化公司
  • 制作外贸网站公司关键词优化公司排名
  • 旅游网站制作 价格万能识图
  • 嘉兴 做网站 推广深圳网站建设系统
  • 百度hi独立站seo是什么意思
  • 西安凡高网络小熊猫seo博客
  • 做论坛网站怎么样备案长春网站关键词排名
  • 兰州网站外包百度广告投放价格
  • 重庆营销网站建设线上推广活动有哪些
  • WordPress比赛竞猜插件宁波seo推广推荐公司
  • 外贸b2c哪个网站好百度指数对比
  • 新网做网站怎么上传做百度推广的网络公司广州
  • 计算机做网站开发需要什么证书网络营销推广经验总结
  • 没有网站可以做域名解析吗关键词排名优化软件价格
  • 做网站需要找什么客户steam交易链接在哪里
  • 深圳网站建设 卓发帖子最好的几个网站
  • 百货批发网站建设在线企业管理培训课程
  • 做微博推广的网站深圳纯手工seo
  • 南宁小程序制作百度seo快排软件