多态的详讲

本文详细介绍了C++中的多态概念,包括多态的构成条件、虚函数、虚函数的重写、override和final关键字的使用。文章还探讨了抽象类、多态的原理,如虚函数表和动态绑定,以及单继承和多继承关系下的虚函数表。通过实例解释了多态的实现原理,展示了如何通过虚函数表找到并调用正确的函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1. 多态的概念

1.1  什么是多态?

2.多态的定义及实现

2.1 多态的构成条件

2.2 虚函数

2.3 虚函数的重写

2.4 override和final关键字

2.5 重载、重写、隐藏的对比

3. 抽象类

3.1 概念

 3.2 接口继承和实现继承

 4. 多态的原理

4.1 虚函数表

4.2 多态的原理

4.3 动态绑定和静态绑定

 5. 单继承和多继承关系的虚函数

5.1 单继承下的虚函数表

5.2 多继承的虚函数表


1. 多态的概念

1.1  什么是多态?

多态的概念:通俗的来说,就是多种形态。可以理解为不同的对象去做同一件事件会产生不同的结果。

举个例子:

比如在抢火车票这个案例,对于普通人则是全价,对于学生是半价,对于军人则是优先购买。

这就是多态的特点:对于不同的对象会产生不同的效果

2.多态的定义及实现

2.1 多态的构成条件

多态是不同继承关系的对象,去调用同一个函数,产生不同的行为,比如Student类继承了Person类,Person类调用其Buyticket函数则是原价买票,而Student调用Buyticket函数则是半价买票。

那么构成多态的条件究竟是什么呢?(最重要的一点之一)

1. 必须是基类的指针或者引用去接收子类对象,然后调用虚函数

2.被调用的函数必须是虚函数,且派生类必须对虚函数进行重写

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "全价 - 100元" << endl;
	}
};

class Student :public Person
{
public:
	virtual void BuyTicket()
	{
		cout << "半价 - 50元" << endl;
	}
};

void Buy(Person* p)
{
	p->BuyTicket();
}
int main()
{
	Person p;
	Student st;

	Buy(&p); //调用的是父类的BuyTicket函数
	Buy(&st);//调用的是子类的BuyTicket函数
	return 0;
}

 

 

2.2 虚函数

什么是虚函数?

被virtual关键字修饰的类成员函数就被称为虚函数

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "全价 - 100元" << endl;
	}
};

2.3 虚函数的重写

虚函数的重写也被称为覆盖,是指派生类中存在和基类完全相同的函数,(即派生类函数和基类函数的参数、名称、返回值相同,也被称为三同),则派生类虚函数为基类虚函数的重写

例如:

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "全价 - 100元" << endl;
	}
};

class Student :public Person
{
public:
	virtual void BuyTicket()
	{
		cout << "半价 - 50元" << endl;
	}
};

虚函数重写的两大例外

1.函数的协变(派生类虚函数和基类虚函数的返回值不相同)

派生类重写基类虚函数时,返回值可以不和基类虚函数相同,基类的返回值为基类的指针或者引用,派生类的范胡子为派生类的指针或者引用,这种重写被称为协变

2. 析构函数的重写

如果基类析构函数是虚函数,那么只要派生类的析构函数完成定义,那么就构成了重写,虽然基类和派生类析构函数的名称不同,看起来没有遵循三同的规则,其实不然,这里是因为编译器将所有的析构函数名处理成了destructor,因此只要基类析构函数是虚函数,那么派生类就重写了基类的函数。

 我们看见基类的指针接受了派生类对象,因此在释放空间时,调用的是派生类重写的析构函数,这里就说明了其实析构函数是完成了重写,如果没有完成重写,则调用的是自身的析构函数

2.4 override和final关键字

由于C++对于重写的实现方式比较严格,但不能保证每次写重写都是正确的,可能也会忘记写一下东西,而这些东西在运行期间是不会被检查出现的,因此C++中提供了两个关键字来帮助我们发现重写中的错误

1. final修饰虚函数,表示该修饰的虚函数不能被重写

 

 2. override修饰虚函数,检查被修饰的虚函数是否完成了重写

如果没有完成对基类虚函数的重写,则会报错

<think>好的,用户想了解Java中的多态概念及细用法,需要我给出细的解释和示例。首先,我得先回忆一下多态的定义和核心要点。多态在Java中通常指的是同一个方法在不同情况下表现出不同的行为,这主要依赖于继承和接口实现。根据之前的引用内容,用户提供的几个例子都涉及父类引用指向子类对象,但访问的是父类的属性,这说明属性没有多态性,而方法有多态性。 接下来,我需要分步骤解释多态的概念、类型、实现机制以及示例。可能需要先定义多态,然后说明编译时多态和运行时多态的区别。编译时多态主要是方法重载,运行时多态则是方法重写和向上转型。这里要特别注意,属性访问没有多态性,所以当父类引用指向子类对象时,访问的是父类的属性,而方法调用则是子类的方法,这需要明确区分。 然后,要给出具体的代码示例,比如父类Animal和子类Dog、Cat的例子,展示方法重写和向上转型的效果。同时要指出属性的访问情况,如引用[1]和[2]中的例子,说明属性由引用类型决定,而方法由实际对象类型决定。 接下来,可能需要讨论多态的应用场景,比如方法参数多态、返回类型多态,以及如何通过接口实现多态。这部分需要结合实际应用,比如集合框架中的List接口不同实现类,或者支付系统的不同支付方式。 注意事项部分需要强调多态的三个必要条件:继承/实现、方法重写、父类引用指向子类对象。还要提到类型转换的问题,比如向下转型时的ClassCastException风险,建议使用instanceof进行检查。 最后,根据用户的要求,生成相关问题。这些问题应该覆盖多态的核心概念、实现细节、应用场景以及可能的问题,比如性能分析、与继承的关系、动态绑定等。 需要确保所有的代码示例正确,并且符合用户提供的引用中的例子,特别是属性访问和方法调用的区别。同时,要使用中文回答,保持结构清晰,分点说明,帮助用户逐步理解。可能还需要检查是否有遗漏的重要知识点,比如多态在设计模式中的应用,或者与其他OOP概念的关系,但根据用户的问题,可能不需要过于深入,保持基础细即可。</think>### Java多态解 #### 一、多态的定义 多态(Polymorphism)是面向对象编程的三大特性之一,指**同一操作作用于不同对象时会产生不同行为**。Java中多态主要通过继承和方法重写实现,表现为两种形式: - **编译时多态**(静态绑定):方法重载(Overload) - **运行时多态**(动态绑定):方法重写(Override)+ 向上转型 #### 二、实现机制 1. **向上转型** 父类引用指向子类对象:`Fu obj = new Zi()` ```java class Animal { void sound(){} } class Dog extends Animal { @Override void sound() { System.out.println("汪汪"); } } Animal animal = new Dog(); //向上转型 animal.sound(); //输出"汪汪",调用子类重写方法[^3] ``` 2. **动态绑定** 方法调用根据实际对象类型决定,在运行时确定: ```java void makeSound(Animal a) { a.sound(); //具体执行哪个子类的sound()由传入对象决定 } ``` #### 三、核心特点 | 特性 | 说明 | |---------------------|---------------------------------------------------------------------| | 方法多态性 | 子类重写父类方法后,通过父类引用调用时会执行子类方法[^4] | | **属性无多态性** | 属性访问由引用类型决定,与对象实际类型无关(见下方示例)[^1][^2] | | 对象类型转换 | 向上转型自动完成,向下转型需要显式转换:`(Zi)fuObj` | #### 四、代码示例 ```java class Person { int age = 30; void mission() { System.out.println("人类使命"); } } class Teacher extends Person { int age = 40; @Override void mission() { System.out.println("教书育人"); } } public class Test { public static void main(String[] args) { Person p = new Teacher(); System.out.println(p.age); //输出30(属性无多态)[^2] p.mission(); //输出"教书育人"(方法有多态)[^3] } } ``` #### 五、应用场景 1. **方法参数多态** ```java public void feed(Animal a) { a.eat(); //可接收所有Animal子类对象 } ``` 2. **集合框架应用** ```java List<String> list = new ArrayList<>(); //接口引用指向实现类 ``` 3. **工厂模式** ```java Payment pay = PaymentFactory.createPayment("Alipay"); pay.pay(); //不同支付方式执行不同逻辑 ``` #### 六、注意事项 1. 实现多态的三要素: - 继承关系/接口实现 - 方法重写 - 父类引用指向子类对象 2. **类型转换异常**处理: ```java if(fuObj instanceof Zi) { Zi zi = (Zi)fuObj; //安全向下转型 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值