C++三大特性——封装、继承、多态(C++基础学习二 )

C++三大特性——封装、继承、多态(C++基础学习二 ),第1张

文章目录
  • C++ 三大特性
    • 访问权限
    • 1. 继承
    • 2. 封装
    • 3. 多态
    • 虚函数(virtual)
      • 虚函数的一些基本概念
      • 为什么需要虚继承
    • 空类
      • 空类的大小不为0,sizeof 为1
    • 抽象类与接口的实现

C++ 三大特性 访问权限

访问限定符: public, protected, private 控制成员变量和成员函数的访问权限

  1. 类内不存在访问权限问题,类外只能访问public 成员;
  2. 无论是公有继承、私有继承或保护继承,私有成员不能被派生类访问,public 和 protected可以;
  3. 对于共有继承,只有基类中的共有成员能够被 派生类对象 访问,保护和私有成员不能被访问。
  4. 对于私有和保护继承,基类中的所有对象均不能被 “派生类对象” 访问。
1. 继承

定义:

让某种类型的对象获得另一个类型对象的属性和方法

功能:

它可以使用现有的类的所有功能,并在无需重新编写原来类的情况下,对这些功能进行扩展

常见的继承有三种方式:

1. 实现继承: 使用基类的属性和方法,而无需额外编码的能力

**2. 接口继承: ** 仅使用属性和方法的名称,但是子类必须提供实现的能力

3. 可视继承: 子窗体(类)使用基窗体(类)的外观和实现代码的能力

例如:

将⼈定义为⼀个抽象类,拥有姓名、性别、年龄等公共属性,吃饭、睡觉等公共⽅法,在定义⼀个具体的⼈时,就可以继承这个抽象类,既保留了公共属性和⽅法,也可以在此基础上扩展跳舞、唱歌等特有⽅法。
2. 封装

定义:

数据和代码捆绑在一起,避免外界干扰和不确定性访问;

功能:

把可观事物封装为一个抽象类,并且类可以把自己的数据和方法只让可信的类或者对象 *** 作,对不可信的进行信息隐藏,例如:将公共的数据或方法使用 public 修饰,而不希望被访问的数据或者方法用 private 修饰

3. 多态

定义:

同一事物表现出不同事物的能力,即向不同对象发送同一消息,不同的对象在接收时会产生不同的行为**(重载实现编译时多态,虚函数实现运行时多态)**

功能:

允许将子类类型的指针 赋值 给父类类型的指针。

实现多态有两种方式:

  1. 覆盖(override): 即虚函数
  2. 重载(overload): 允许多个参数不同的同名函数

例如:

基类是一个抽象对象——人,那学生、老师等等都是人。

虚函数(virtual)

当基类希望派生类定义适合自己的版本,那么就将这些函数声明为 虚函数

虚函数依赖虚函数表工作,表来保存虚函数的地址,当我们用基类指针指向派生类时,虚表指针指向派生类的虚函数表

这个机制可以保证,派生类中的虚函数可以被调用到

虚函数的一些基本概念

1. 虚函数是动态绑定的

使用虚函数的指针或者引用,能够找到实际类的对应函数,而非执行定义类的函数,这是虚函数的基本功能。

2. 多态 : 不同继承关系的类对象,调用同一函数产生不同的行为

  • 调用函数的对象必须是指针或引用
  • 被调用的函数必须是 虚函数 , 且完成了虚函数的重写。

3. 动态绑定绑定的是动态类型

所对应的函数或属性依赖于对象的动态类型,发生在运行期

4. 构造函数不能是虚函数

5. 虚函数的工作方式

依赖虚函数表工作的,表来保存虚函数的地址,当我们用基类指针指向派生类时,虚表指针指向派生类的虚函数表。

6. 析构函数可以是虚函数,并且,在一个复杂类结构中,析构函数往往大多都为虚函数

7. 将一个函数定义为纯虚函数

实际上这个 *** 作是通过,将这个类定义为抽象类,不能实例化对象;

纯虚函数通常没有定义体,但是也完全可以拥有。

8. inline, static, constructor 三种函数都不能带有virtual 关键字

(1) inline 在编译时展开,必须要有实体

(2) static 属于类自身的类相关,必须有实体

​ static 成员没有this 指针,而虚函数是通过对象来调用,有隐藏的this 指针。

(3)虚函数是基于内存空间的(vtable), constructor 如果是虚的,那么调用时也需要到内存空间中寻找,但是constructor是虚的情况下是找不到的,因为constructor 自身都不存在了,创建不到class的实例,没有实例,class的成员都不能访问。

9. 析构函数可以是纯虚的

但是析构函数必须有钉一体,因为析构函数的调用是在子类中隐去的

10. 派生类的override虚函数定义必须与父类完全一致

除了一个特例,如果父类返回值是一个指针或者引用,子类override时,可以返回这个指针或引用的派生。

为什么需要虚继承

1. 为了解决多继承时的命名冲突和冗余数据问题

C++提出了虚继承,使得在派生类中只保留一份间接基类的成员。其中多继承是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。

2. 虚继承的目的是让某个类做出声明,承诺愿意共享它的基类

其中,被共享的基类称为 虚基类(Virtual Base Class).

使用多继承经常出现二义性,必须十分小心:

一般只有在比较简单和不易出现二义性的情况下,或者要求使用的情况下 才会使用多继承,能用单一继承解决的问题,一般不使用多继承。

空类 空类的大小不为0,sizeof 为1

类的实例化是在内存中分配一块地址,因此每个实例在内存中均有独一无二的地址。

同样,空类也会实例化,所以编译器会给空类隐含的添加一个地址,这样就可以保证空类在实例化之后就有独一无二的地址,所以空类的sizeof 为1 ,而不是0

class A {
    virtual void f() {}
};
class B: public A{}

注意:此时类A和类B都不是空类,其sizeof 都为4,因为他们都具有虚函数表

class A {};
class B:public virtual A{};

此时,类A是空类,其大小为1,; 而类B不为空类,其sizeof 是4.因为含有虚函数表的地址。

多重继承的空类的大小也为1.

class Father1{};
class Father2{};
class Child: public Father1, public Father2{};

Father1, Father2, Child的大小均为1。

何时共享虚函数地址表:

如果派生类继承的第一个是基类,且该基类定义了虚函数地址表,则派生类就共享该表首地址占用的存储单元。

class X{}; //sizeof(X):1
class Y : public virtual X {}; //sizeof(Y):4
class Z : public virtual X {}; //sizeof(Z):4
class A : public virtual Y {}; //sizeof(A):8
class B : public Y, public Z{}; //sizeof(B):8
class C : public virtual Y, public virtual Z {}; //sizeof(C):12
class D : public virtual C{}; //sizeof(D):16
抽象类与接口的实现

接口描述了类的行为和功能,而不需要完成类的特定实现; C++接口是使用抽象类来实现的。

  1. 类中至少有一个函数被声明为虚函数,则这个类就是抽象类。纯虚函数是通过在声明中,使用 “= 0 ”来指定的。
  2. 设计抽象类(通常称为 ABC)的目的,是为了给其他类提供一个可以继承的适当的基类。抽象类不能用于实例化,它只能作为接口使用。
class Shape
{
public:
	// 提供接⼝框架的纯虚函数
	virtual int getArea() = 0;
	void setWidth(int w)
	{
		width = w;
	}
	void setHeight(int h)
	{
		height = h;
	}
protected:
	int width;
	int height;
};

// 派⽣类
class Rectangle: public Shape
{
public:
	int getArea()
	{
		return (width * height);
	}
};

class Triangle: public Shape
{
public:
	int getArea()
	{
	return (width * height)/2;
	}
};

主函数:

Rectangle Rect;
Triangle Tri;
Rect.setWidth(5);
Rect.setHeight(7);
Rect.getArea(); //35
Tri.setWidth(5);
Tri.setHeight(7);
Tri.getArea(); //17

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/921523.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存