类之间可以建立联系,这就使得类可以有某种关系

类之间的关系

has-A:包含关系,一个类使用另一个已经定义好的类的数据
uses-A:使用关系,友元或者对象参数传递
is-A:是的关系,这就是继承,具有传递性不具有对称性
继承是类之间定义的一种重要关系,一个B类继承A类,或称从类A派生类B,类A称为基类(父类),类B称为派生类(子类)

基类和派生类

类继承关系的语法形式

class 派生类名:基类名表
{数据成员和成员函数声明
};

基类名表构成:访问控制 基类名1, 访问控制 基类名2,···, 访问控制 基类名n
访问控制 表示派生类对基类的继承方式,使用关键字:

  • public 公有继承
  • private 私有继承
  • protected 保护继承

访问控制

派生类对基类成员的使用,与继承访问控制和基类中成员性质有关
公有继承:基类的公有成员 -> 派生类的公有成员,基类的保护成员 -> 派生类的保护成员
私有继承:基类的公有成员和保护成员 -> 派生类的私有成员
保护继承:基类的公有成员和保护成员 -> 派生类的保护成员
不论种方式继承基类,派生类都不能直接使用基类的私有成员

重名成员

派生类定义了与基类同名的成员,在派生类中访问同名成员时屏蔽了基类的同名成员
在派生类中使用基类的同名成员,显式地使用类名限定符:
类名::成员

派生类中的静态成员

基类定义的静态成员,将被所有派生类共享
根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具有不同的访问性质
派生类中访问静态成员,用以下形式显式说明:
通过类:类名::成员
通过对象:对象名.成员

基类的初始化

建立一个类层次后,通常创建某个派生类的对象,包括使用基类的数据和函数
C++提供一种机制,在创建派生类对象时用指定参数调用基类的构造函数来初始化派生类继承基类的数据
派生类构造函数声明为

派生类构造函数(变元表):基类(变元表),对象成员1(变元表)···对象成员n(变元表);

构造函数执行顺序:基类 -> 对象成员 -> 派生类

继承的应用实例

#include <iostream>
#include <iomanip>using namespace std;class Point
{friend ostream &operator<< (ostream &, const Point &);
public:Point(int = 0, int = 0);//带默认参数的构造函数void setPoint(int, int);//对点坐标数据赋值int getX() const{return x;}int getY() const{return y;}
protected:int x, y;//Point类的数据成员
};class Circle :public Point
{friend ostream &operator<<(ostream &, const Circle &);//友员函数
public:Circle(double r = 0.0, int x = 0, int y = 0);//构造函数void setRadius(double);/*置半径*/double getRadius() const;/*返回半径*/double area() const;//返回面积
protected:double radius;//数据成员,半径
};class Cylinder :public Circle
{friend ostream & operator<<(ostream &, const Cylinder &);//友员函数
public:Cylinder(double h = 0.0, double r = 0.0, int x = 0, int y = 0);//构造函数void setHeight(double);/*置高度值*/double getHeight() const;/*返回高度值*/double area() const;/*返回面积*/double volume() const;/*返回体积*/
protected:double height;//数据成员,高度
};//Point 类的成员函数
//构造函数,调用成员函数对x,y作初始化
Point::Point(int a, int b)
{setPoint(a, b);
}
//对数据成员置值
void Point::setPoint(int a, int b)
{ x = a;y = b;
}
//重载插入算符,输出对象数据
ostream &operator<<(ostream &output, const Point &p)
{output << '[' << p.x << "," << p.y << "]";return output;
}//Circle 类的成员函数
//带初始化式构造函数,首先调用基类构造函数
Circle::Circle(double r, int a, int b):Point(a, b)
{ setRadius(r);
}
//对半径置值
void Circle::setRadius(double r)
{radius = (r >= 0 ? r : 0);
}
// 返回半径值
double Circle::getRadius() const
{ return  radius;
}
// 计算并返回面积值
double Circle::area() const
{ return  3.14159 * radius * radius;
}
// 输出圆心坐标和半径值
ostream & operator<< (ostream &output, const Circle &c)
{output << "Center = " << '[' << c.x << "," << c.y << "]" << "; Radius = "<< setiosflags(ios::fixed | ios::showpoint) << setprecision(2) << c.radius;return  output;
}//Cylinder 类的成员函数
//带初始化式构造函数,首先调用基类构造函数
Cylinder::Cylinder(double h, double r, int x, int y):Circle(r, x, y)
{ setHeight(h);
}
// 对高度置值
void Cylinder::setHeight(double h)
{height = (h >= 0 ? h : 0);
}
// 返回高度值
double Cylinder::getHeight() const
{return height;
}
// 计算并返回圆柱体的表面积
double Cylinder::area() const
{return  2 * Circle::area() + 2 * 3.14159*radius*height;
}
// 计算并返回圆柱体的体积
double Cylinder::volume() const
{return  Circle::area()*height;
}
// 输出数据成员圆心坐标、半径和高度值
ostream &operator<< (ostream &output, const Cylinder &cy)
{output << "Center = " << '[' << cy.x << "," << cy.y << "]" << "; Radius = "<< setiosflags(ios::fixed | ios::showpoint) << setprecision(2) << cy.radius<< "; Height = " << cy.height << endl;return output;
}int main()
{Point p(72, 115);//定义点对象并初始化cout << "The initial location of p is " << p << endl;p.setPoint(10, 10);//置点的新数据值cout << "\nThe new location of p is " << p << endl;//输出数据Circle c(2.5, 37, 43);//定义圆对象并初始化cout << "\nThe initial location and radius of c are\n" << c << "\nArea = " << c.area() << "\n";//置圆的新数据值c.setRadius(4.25);c.setPoint(2, 2);//输出圆心坐标和圆面积cout << "\nThe new location and radius of c are\n" << c << "\nArea = " << c.area() << "\n";Cylinder cyl(5.7, 2.5, 12, 23);//定义圆柱体对象并初始化//输出圆柱体各数据和表面积,体积cout << "\nThe initial location, radius ang height of cyl are\n" << cyl<< "Area = " << cyl.area() << "\nVolume = " << cyl.volume() << '\n';//置圆柱体的新数据值cyl.setHeight(10);cyl.setRadius(4.25);cyl.setPoint(2, 2);cout << "\nThe new location, radius ang height of cyl are\n" << cyl<< "Area = " << cyl.area() << "\nVolume = " << cyl.volume() << "\n";system("pause");return 0;
}

多继承

一个类有多个直接基类的继承关系称为多继承
多继承声明语法

class 派生类名:访问控制 基类名1, 访问控制 基类名2,···,访问控制 基类名n
{数据成员和成员函数声明
};

类C可以根据访问控制同时继承类A和类B的成员,并添加自己的成员

class C:public A, public B

多继承的派生类构造和访问

  • 多个基类的派生类构造函数可以用初始式调用基类构造函数初始化数据成员
  • 执行顺序与单继承构造函数情况类似。多个直接基类构造函数执行顺序取决于定义派生类时指定的各个继承基类的顺序
  • 一个派生类对象拥有多个直接或间接基类的成员。不同名成员访问不会出现二义性。如果不同的基类有同名成员,派生类对象访问时应该加以识别
    e.g.
class Base1
{
public:Base1(int x){value = x;}int getData() const{return value;}
protected:int value;
};class Base2
{
public:Base2(char c){letter = c;}char getData() const{return letter;}
protected:char letter;
};class Derived : public Base1, public Base2
{friend ostream &operator<< (ostream &, const Derived &);
public:Derived(int, char, double);double getReal() const;
private:double real;
};

虚基类

如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性

class B
{
public:int b;
};
class B1:public B
{
private:int b1;
};
class B2:public B
{
private:int b2;
};
class C:public B1, public B2
{
public:int f();
private:int d;
};
C c;
c.B;// error
c.B::b;// error,从哪里继承的?
c.B1::b;// ok,从B1继承的
c.B2::b;// ok ,从B2继承的

建立 C 类的对象时,B 的构造函数将被调用两次:一次由B1调用,另一次由 B2 调用,以初始化 C 类的对象中所包含的两个 B 类的子对象

  • 如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性
  • 如果在多条继承路径上有一个公共的基类,那么在继承路径的某处汇合点,这个公共基类就会在派生类的对象中产生多个基类子对象
  • 要使这个公共基类在派生类中只产生一个子对象,必须对这个基类声明为虚继承,使这个基类成为虚基类
  • 虚继承声明使用关键字:virtual
class B
{
public:int b;
};
class B1:virtual public B
{
private:int b1;
};
class B2:virtual public B
{
private:int b2;
};
class C:public B1, public B2
{
private:float d;
};
C cc;
cc.b;// ok

由于类 C 的对象中只有一个 B 类子对象,名字 b 被约束到该子对象上,所以,当以不同路径使用名字 b 访问 B 类的子对象时,所访问的都是那个唯一的基类子对象。即cc.B1::bcc.B2::b引用是同一个基类 B 的子对象

面向对象中的继承指类之间的父子关系

  1. 子类拥有父类的所有成员变量和成员函数
  2. 子类就是一种特殊的父类
  3. 子类对象可以当作父类对象使用
  4. 子类可以拥有父类没有的方法和属性

C++中的继承方式(public、private、protected)会影响子类的对外访问属性

  • public继承:父类成员在子类中保持原有访问级别
  • private继承:父类成员在子类中变为private成员
  • protected继承:父类中public成员会变成protected,父类中protected成员仍然为protected,父类中private成员仍然为private
    注意:private成员在子类中依然存在,但是却无法访问到。

继承总结

  • 继承是面向对象程序设计实现软件重用的重要方法。程序员可以在已有基类的基础上定义新的派生类。
  • 单继承的派生类只有一个基类。多继承的派生类有多个基类。
  • 派生类对基类成员的访问由继承方式和成员性质决定。
  • 创建派生类对象时,先调用基类构造函数初始化派生类中的基类成员。调用析构函数的次序和调用构造函数的次序相反。
  • C++提供虚继承机制,防止类继承关系中成员访问的二义性。
  • 多继承提供了软件重用的强大功能,也增加了程序的复杂性

转载于:https://www.cnblogs.com/cj5785/p/10664728.html

C++学习笔记-继承相关推荐

  1. java继承关键字super_java学习笔记-继承中super关键字

    背景: 在java继承的概念中我们得知,被声明为私有的类成员对所属的类来说仍然是私有的.类之外的任何代码都不能访问,包括子类. super关键字的两种用法: 1.用于调用超类的构造函数: 2.用于访问 ...

  2. Java学习笔记--继承和多态(下)

    1.通过继承来开发超类(superclass) 2.使用super 关键词唤起超类的构造方法 3.在超类中覆盖方法 4.区分override和overload 5.在Object类中探索toStrin ...

  3. Python 学习笔记 -- 继承与多态(入门级实例)

    1 #继承 2 #假设有不同品种的鱼,它们的蛋白质含量都不同,那么我们吃掉这些鱼获得的效果也应该不同 3 #---------------------------------------------- ...

  4. C++学习笔记-----继承体系中函数的重载,覆盖和隐藏的区别

    1.重载,在同一个作用域中定义的同名不同参的一些函数为重载. 2.隐藏,若在基类中定义了某一non_virtual函数,在派生类重存在同名函数(不需要参数列表相同),基类的该函数在派生类中是不可见的, ...

  5. 【b站黑马程序员C++视频学习笔记-继承方式】

    继承方式 有以下三种继承方式: 公共继承public 保护继承protected 私有继承private 继承之后访问权限如下: 类名/属性 int a int b int c 父类A public ...

  6. c++入门学习笔记继承

    ***继承,面向对象程序设计的上方宝剑,有了它上下通吃---Skyala*** 人(类)->父母(对象)->子女(继承.多重继承)->子孙(多态性)---哇,My God!多么完美的 ...

  7. python编程语言继承_python应用:学习笔记(Python继承)

    学习笔记(Python继承)Python是一种解释型脚本语言,可以应用于以下领域: web 和 Internet开发 科学计算和统计 人工智能 教育 桌面界面开发 后端开发 网络爬虫 有几种叫法(父类 ...

  8. C# 学习笔记(5) 继承

    C# 学习笔记(5) 继承 我们可能会在一些类中,写一些重复的成员,继承就是为了避免重复写这些成员,将这些成员 单独的封装到一个类中,作为这些类的父类.一个类在需要这些重复的成员时,直接继承父类,这些 ...

  9. java学习笔记6--类的继承、Object类

    接着前面的学习: java学习笔记5--类的方法 java学习笔记4--类与对象的基本概念(2) java学习笔记3--类与对象的基本概念(1) java学习笔记2--数据类型.数组 java学习笔记 ...

最新文章

  1. 毒霸主程序集成反流氓
  2. Java记录 -24- equals方法重写
  3. centos7 安装 openssl
  4. Hadoop学习笔记—4.初识MapReduce
  5. ubuntu9.10安装Tweak
  6. ASP.NET服务器应用程序不可用
  7. SpringMVC简介-传统的Model1和Model2/MVC思想及其优势/Spring MVC的优势
  8. SAP CRM WebClient UI calculated fields的工作原理
  9. 对于华为,英特尔与微软表示继续提供支持;亚马逊亲证云计算服务出现宕机;中国移动5G套餐曝光,每月都含200G流量……...
  10. 设计模式---工厂模式
  11. 我就拜你为师的飞秋爱好者
  12. git clone 一部分_别再往 Git 仓库中放敏感信息了,不安全!
  13. 把js封装到html,什么是javascript封装?
  14. 【postgres】postgres 数据库迁移
  15. 神经网络拟合函数表达式,神经网络拟合函数matlab
  16. 黑苹果、win双系统,丢失黑苹果引导,如何修复黑苹果的引导
  17. C# 舒特二次开发采集考勤记录并同步设备时间
  18. RHCSA认证培训+考试七天实录(一)
  19. 不同的「火」在舌頭上的表現也不一樣
  20. node.js实现图片裁剪+获取图片大小+加logo水印

热门文章

  1. Option键用的好,鼠标用的少(这6个你绝对不知道的...)
  2. python代码进去docker容器内_python脚本监控docker容器
  3. mysql主从代替技术_mysql主从复制及失败切换
  4. ospfdr选举规则_ospf DR和BDR选举注意的问题
  5. greenplum 查询出来的数字加减日期_POLA宝丽美白精华怎么查看生产日期保质期?保质期时间是几年的?查批号在哪里查?...
  6. 【干货】JS版汉字与拼音互转终极方案,附简单的JS拼音输入法
  7. mysql 多值属性_数据库 名词解释:单值属性和多值属性
  8. html引入vue不兼容ie11,关于vue.js:iview按需引入ie11不兼容报无效字符问题解决
  9. vm虚拟机系统界面无法全屏
  10. nagios监控mysql服务_nagios监控mysql及邮件报警