C++多态性原理
C语言中的多态性
point operator++(); 符“++”
point operator--(); 符“--”
//重载前置运算
//重载前置运算
point point::operator++() { if(x<640) ++x; if(y<480) ++y; return *this; } point point::operator--() { if(x>0) --x; if(y>0) --y; return *this; }
数时,如果某个对象使用重载了的成员函数,自身的数据可以直接访问,
就不需要再放在参数表中进行传递,少了的操作数就是该对象本身。
第8章 多态性
8.2.2 运算符重载为成员函数
运算符重载实质上就是函数重载,当运算符重载为成员函数 之后,它就可以自由地访问本类的数据成员了。实际使用时,总 是通过该类的某个对象来访问重载的运算符。如果是双目运算符, 一个操作数是对象本身的数据,由this指针指出,另一个操作数则 需要通过运算符重载函数的参数表来传递;如果是单目运算符, 操作数由对象的this指针给出,就不再需要任何参数。下面分别介 绍这两种情况。 1.双目运算:oprdl B oprd2 对于双目运算符B,如果要重载B为类的成员函数,使之能够 实现表达式oprdl B oprd2(其中oprdl为A类的对象),则应当把B重 载为A类的成员函数,该函数只有一个形参,形参的类型是oprd2 所属的类型。经过重载之后,表达式oprdl B oprd2就相当于函数 调用oprdl.operator B (oprd2)。
8.2.3 运算符重载为友元函数
运算符也可以重载为类的友元函数,这样它就可以自由地访问 该类的任何数据成员。这时,运算所需要的操作数都需要通过函
C语言中的多态
C语⾔中的多态⼀、多态的主要特点1、继承体系下。
继承:是⾯向对象最显著的⼀个特性。
继承是从已有的类中派⽣出新的类,新的类能吸收已有类的数据属性和⾏为,并能扩展新的能⼒,已有类被称为⽗类/基类,新增加的类被称作⼦类/派⽣类。
2、⼦类对⽗类的虚函数进⾏重写。
3、虚表。
在⾯向对象语⾔中,接⼝的多种不同现⽅式即为多态。
同⼀操作作⽤于不同的对象,可以有不同的解释,产⽣不同的执⾏结果,这就是多态性。
简单说就是允许基类的指针指向⼦类的对象。
⼆、代码实现1、C++中的继承与多态1 class Base2 {3 public:4 virtual void fun() {} //基类函数声明为虚函数5 int B1;6 };7 class Derived :public Base //Derived类公有继承Base类8 {9 public:10 virtual void fun() { //函数重写,此时基类函数可以声明为虚函数,也可以不声明11 cout << "D1.fun" << endl;12 }13 int D1;14 };15 int main(){16 Base b1; //创建⽗类对象17 Derived d1;//创建⼦类对象1819 Base *p1 = (Base *)&d1;//定义⼀个⽗类指针,并通过⽗类指针访问⼦类成员20 p1->fun();2122 Derived *p2 = dynamic_cast<Derived*> (&b1); //dynamic_cast⽤于将⼀个⽗类对象的指针转换为⼦类对象的指针或引⽤(动态转换)23 p2->fun();2425 getchar();26 return 0;27 }2. C语⾔实现C++的继承与多态1 typedef void(*FUNC)(); //定义⼀个函数指针来实现对成员函数的继承2 struct _Base //⽗类3 {4 FUNC _fun;//由于C语⾔中结构体不能包含函数,故借⽤函数指针在外⾯实现5 int _B1;6 };7 struct _Derived//⼦类8 {9 _Base _b1;//在⼦类中定义⼀个基类的对象即可实现对⽗类的继承10 int _D1;11 };12 void fb_() //⽗类的同名函数13 {14 printf("_b1:_fun()\n");15 }16 void fd_() //⼦类的同名函数17 {18 printf("_d1:_fun()\n");19 }20 int main() {21 _Base _b1;//定义⼀个⽗类对象_b122 _Derived _d1;定义⼀个⼦类对象_d12324 _b1._fun = fb_;//⽗类的对象调⽤⽗类的同名函数25 _d1._b1._fun = fd_;//⼦类的对象调⽤⼦类的同名函数2627 _Base *_p1 = &_b1;//定义⼀个⽗类指针指向⽗类的对象28 _p1-> _fun(); //调⽤⽗类的同名函数2930 _p1 = (_Base *)&_d1;//让⽗类指针指向⼦类的对象,由于类型不匹配所以要进⾏强转31 _p1->_fun(); //调⽤⼦类的同名函数3233 getchar();34 return 0;35 }。
C_多态
C#的多态一、什么是多态可以把一组对象放到一个数组中,然后调用它们的方法,在这种场合下,多态性作用就体现出来了,这些对象不必是相同类型的对象。
当然,如果它们都继承自某个类,你可以把这些派生类,都放到一个数组中。
如果这些对象都有同名方法,就可以调用每个对象的同名方法。
同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。
多态性通过派生类重载基类中的虚函数型方法来实现。
在面向对象的系统中,多态性是一个非常重要的概念,它允许客户对一个对象进行操作,由对象来完成一系列的动作,具体实现哪个动作、如何实现由系统负责解释。
“多态性”一词最早用于生物学,指同一种族的生物体具有相同的特性。
在C#中,多态性的定义是:同一操作作用于不同的类的实例,不同的类将进行不同的解释,最后产生不同的执行结果。
C#支持两种类型的多态性:● 编译时的多态性编译时的多态性是通过重载来实现的。
对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。
● 运行时的多态性运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。
C#中,运行时的多态性通过虚成员实现。
编译时的多态性为我们提供了运行速度快的特点,而运行时的多态性则带来了高度灵活和抽象的特点。
二、实现多态多态性是类为方法(这些方法以相同的名称调用)提供不同实现方式的能力。
多态性允许对类的某个方法进行调用而无需考虑该方法所提供的特定实现。
例如,可能有名为Road 的类,它调用另一个类的Drive 方法。
这另一个类Car 可能是SportsCar 或SmallCar,但二者都提供Drive 方法。
虽然Drive 方法的实现因类的不同而异,但Road 类仍可以调用它,并且它提供的结果可由Road 类使用和解释。
可以用不同的方式实现组件中的多态性:● 接口多态性。
● 继承多态性。
● 通过抽象类实现的多态性。
接口多态性多个类可实现相同的“接口”,而单个类可以实现一个或多个接口。
c 多态性 课件 讲座
5.3.1 类以外的运算符重载
对基本的数据类型,C++提供了许多预定义的运算符,如“+”、 “-”、“*”、“/”、“=” 等,若有一个复数类 complex: class complex{ public: double real,imag; complex(double r=0,double i=0) {real=r;imag=i;} }; 若要把类complex的两个对象com1和com2加在一起,下面的语句 是不能实现的: void main() { complex com1(1.1,2.2), com2(3.3,4.4), total; total=com1+com2; //错误 //... } 错误原因是类complex的类型不是基本数据类型,而是用户自定义 6 的数据类型。C++还是无法直接将两个complex类对象相加。
12
2.双目运算符重载 当用友元函数重载双目运算符时,两个操作数都要传给运 算符函数。
例5.3 友元函数重载双目运算符
两个复数a+bi和c+di进行加、减、乘、除的方法如下: 加法:(a+bi)+(c+di)=(a+c)+(b+d)i 减法:(a+bi)-(c+di)=(a-c)+(b-d)i 乘法:(a+bi)*(c+di)=(ac-bd)+(ad+bc)i 除法:(a+bi)/(c+di)=((a+bi)*(c-di))/(c*c+d*d)
类外部的运算符函数 为了表达上的方便,人们希望预定义的内部运算符(如“+”、“-”、 “*”、“/”等)在特定类的对象上以新的含义进行解释,如希 望能够实现total=com1+com2,这就需要用重载运算符来解决。 C++为运算符重载提供了一种方法,即在进行运算符重载时, 必须写一个运算符函数,其名字为operator后随一个要重载的运 算符。例如,要重载“+”号,应该写一个名字为 operator+ 的 函数。 表5.1 运算符函数
CC++中多态性详解及其作用介绍
CC++中多态性详解及其作⽤介绍⽬录概述静态多态函数重载运算符重载动态多态⾮动态动态概述多态性 (polymorphism) 是⾯向对象程序设计的⼀个重要特征. 利⽤多态性扩展设计和实现⼀个易于扩展的系统.C++ 中多态性:同⼀函数名可以实现不同的功能⽤⼀个函数名调⽤不同内容的函数完成不同的⼯作静态多态静态多态 (static polymorphism) 是通过函数的重载实现的, 包括函数的重载和运算符重载. 在程序编译时系统就能觉得调⽤哪个函数.函数重载int main() {cout << max(1,2) << endl;cout << max(1.2, 2.3) << endl;return 0;}int max(int a, int b) {return (a > b) ? a:b;}double max(double a, double b){return (a > b) ? a:b;}输出结果:22.3运算符重载int main() {Complex c1(2, 4), c2(6, 10);c1 = c1 + c2;c1.display();return 0;}Complex Complex::operator+(Complex &c) {return Complex(real + c.real, imag + c.imag);}输出结果:(8, 14i)动态多态动态多态 (dynamic polymorphism) 是在程序运⾏中才动态地确定操作所针对的对象.⾮动态Person 类:#ifndef PROJECT6_PERSON_H#define PROJECT6_PERSON_H#include <iostream>#include <string>using namespace std;class Person {private:string name; // 姓名char gender; // 性别public:Person(string n, char g) : name(n), gender(g) {}void display() {cout << "name: " << name << endl;cout << "gender: " << gender << endl;}};#endif //PROJECT6_PERSON_HTeacher 类:#ifndef PROJECT6_TEACHER_H#define PROJECT6_TEACHER_H#include <iostream>#include <string>#include "Person.h"using namespace std;class Teacher : public Person {private:string title; // 头衔public:Teacher(string n, char g, string t) : Person(n, g), title(t) {}void display() {Person::display();cout << "title: " << title << endl;}};#endif //PROJECT6_TEACHER_Hmain:#include <iostream>#include "Person.h"#include "Teacher.h"int main() {// 创建对象Person p1("王叔叔", 'm'), *pt; // 指针类型为Teacher t1("王⽼师", 'f', "教导主任");pt = &p1;pt->display();pt = &t1;pt->display();return 0;}输出结果:name: 王叔叔gender: mname: 王⽼师gender: f我们可以发现 Teacher 对象的头衔并没有输出, 因为 pt 指针的类型是 Person, 调⽤的是 Person 的display()函数.动态我们把show()函数声明为虚函数.Person 类:#ifndef PROJECT6_PERSON_H#define PROJECT6_PERSON_H#include <iostream>#include <string>using namespace std;class Person {private:string name; // 姓名char gender; // 性别public:Person(string n, char g) : name(n), gender(g) {}virtual void display() {cout << "name: " << name << endl;cout << "gender: " << gender << endl;}};#endif //PROJECT6_PERSON_Hmain:#include <iostream>#include "Person.h"#include "Teacher.h"int main() {// 创建对象Person p1("王叔叔", 'm'), *pt; // 指针类型为Teacher t1("王⽼师", 'f', "教导主任");pt = &p1;pt->display();pt = &t1;pt->display();return 0;}输出结果:name: 王叔叔gender: mname: 王⽼师gender: ftitle: 教导主任到此这篇关于C/C++中多态性详解及其作⽤介绍的⽂章就介绍到这了,更多相关C++多态性内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。
C语言实现程序的多态性
了深入的认识。这时候你讶异的开始质疑了:“多态,那是 面向对象编程才有的技术,C 语
言是面向过程的啊!”而我想说的是,C 语言作为一种编程语言,也许并不是为了面向对象
编程而设计,但这并不意味着它不能实现面向对象编程所能实现的功能,就比如说,多态性。
在本文中我们使用一个简单的单链表作为例子,展示 C 语言是如何体现多态性的。
回页首
结构体:不得不说的故事
许多从写 C 代码开始,逐渐走向 C++ 的程序员都知道,其实 C++ 里面的 class,其前身
正是 C 语言中的 structure。很多基于 C 语言背景介绍 C++ 的书籍,在介绍到 class 这
一章的时候都会向读者清晰地展示,一个 C 语言里的 structure 是怎样逐渐变成一个典型
// 初始化链表 // 建立新节点 // 在已有链表的表头进行插入节点操作
// 输出链表中数据到控制台
我们来看看现在这个链表和刚才那个只能存储整型数据的链表的区别。 当你把 Node 结构体里面的成员定义为一个整型数据,就好像把这个链表节点打造成了一 个大小形状固定的盒子,你定义一个链表节点,程序进行编译的时候编译器就为你打造一 个
就是它。
下面来改造我们的链表代码,在 linkList.h 里,如下:
typedef struct Node* linkList;
struct Node
// 链表节点
{
void *data;
// 存储的数据指针
linkList next;
// 指向下一个链表节点
};
linkList initialLinklist(); link newLinkList (void *data); void insertFirst(linkList h, void *data); void linkListOutput(linkList h);
c语言中多态的定义及实现方式
c语言中多态的定义及实现方式C语言是一种面向过程的编程语言,不支持面向对象编程的特性,如多态、继承和封装等。
但是,我们可以通过一些技巧来实现类似于面向对象编程中的多态性。
在本文中,我们将介绍C语言中多态的定义、实现方式以及举出一些例子。
1.多态的定义多态是面向对象编程中的一个重要概念。
它指的是不同对象对同一消息作出不同响应的能力。
在C语言中,我们可以通过函数指针、结构体和联合体等技术来实现多态性。
下面是多态的定义:多态是指在不同的对象上调用同一方法,而这些对象会根据所属类的不同产生不同的行为。
换句话说,多态是指一个接口,多种实现。
1.多态的实现方式在C语言中,我们可以通过以下方式来实现多态性:2.1 函数指针函数指针是指向函数的指针变量。
我们可以将不同的函数指针赋值给同一个函数指针变量,从而实现多态性。
例如:#include <stdio.h>void add(int a,int b){printf("%d + %d = %d\n", a, b, a + b);}void sub(int a,int b){printf("%d - %d = %d\n", a, b, a - b);}int main(){void(*p)(int,int);int a =10, b =5;p = add;p(a, b);p = sub;p(a, b);return0;}在上面的例子中,我们定义了两个函数add和sub,它们实现了两种不同的行为。
我们定义了一个函数指针p,它可以指向这两个函数。
在不同的情况下,我们将p 指向不同的函数,从而实现了多态性。
2.2 结构体结构体是一种自定义的数据类型,它可以包含多个不同类型的成员。
我们可以通过结构体来实现多态性。
例如:#include <stdio.h>typedef struct Animal{void(*speak)();} Animal;typedef struct Cat{Animal base;} Cat;typedef struct Dog{Animal base;} Dog;void cat_speak(){printf("Meow!\n");}void dog_speak(){printf("Woof!\n");}int main(){Cat cat;Dog dog;cat.base.speak = cat_speak;dog.base.speak = dog_speak;cat.base.speak();dog.base.speak();return0;}在上面的例子中,我们定义了一个Animal结构体和两个派生结构体Cat和Dog。
C 程序设计 教学课件 ppt 第11章_多态性
▫ 分析
这个结果和例10-7的输出结果很不一样。Base1声明Show
为基函数,派生类Base2,C重写了该函数,通过向上转
型,分别传递Base1,Base2,C的指针给CallShow函数
时,虽然在CallShow函数中的语句是“pb1->Show();”,
其中pb1被声明为Base1的指针,但是调用的函数确分别
▫ 参数多态:与将在第14章中介绍的类模板相关联 ▫ 前两种称为专用多态,后两种称为通用多态
C++程序设计,郑莉,清华大学 4
11.2 虚函数
11.2.1 一般虚函数成员
• 将类的某个成员函数用virtual关键字声明得到的函 数就是虚函数
• 定义格式为:
virtual 返回类型 函数名(形参表) {
class C:public Base {
public:
C() { ip = new int(0); } //类C构造函数,初始化成员
~C();
//类C析构函数
private:
int * ip; };
C::~C() {
delete ip;
cout<<"ip has been deleted"<<endl;
};
class C:public Base2 {
void Show() { cout<<"C::Show()"<<endl; }
//公共函数Show
};
C++程序设计,郑莉,清华大学 6
11.2 虚函数
11.2.1 一般虚函数成员
void CallShow(Base1* pb1) { //全局函数,参数为Base1的指针
c多态的理解
c多态的理解
在C++中,如果一个基类拥有一个虚函数,那么子类可以重写这个函数,实现多态性。
当我们调用这个函数时,会根据对象类型调用不同的函数,这就是多态的核心。
多态性有助于实现代码的灵活性和可重用性。
如果我们需要添加一个新的子类,我们只需要继承基类并重写虚函数即可,不需要修改已有的代码。
多态性还有助于实现面向对象编程的封装性。
我们可以隐藏类的实现细节,在外部代码中只使用基类的指针或引用,实现对类的抽象。
需要注意的是,在使用多态性时,我们需要使用指针或引用来访问对象,否则无法实现多态性。
此外,虚函数的使用会引入一定的运行时开销,因此需要谨慎使用。
综上所述,多态性是C++中的一个重要概念,可以帮助我们实现代码的灵活性、可重用性和封装性。
- 1 -。
最新C 程序设计 第12章多态性与虚函数课件ppt
C++规定,当一个成员函数被声明为虚函数后,其 派生类中的同名函数都自动成为虚函数。因此在派 生类重新声明该虚函数时,可以加virtual,也可以 不加,但习惯上一般在每一层声明该函数时都加 virtual,使程序更加清晰。
如果在派生类中没有对基类的虚函数重新定义,则 派生类简单地继承其直接基类的虚函数。
class Student { protected: string name; public: Student(string n):name(n) {} virtual void PrintInfo(); };
void Student::PrintInfo() { cout<<"name: "<<name<<endl; }
class Graduate:public Student { protected: string advisor; public: Graduate(string n,string a):Student(n),advisor(a) {} void PrintInfo(); };
void Graduate::PrintInfo() { cout<<"name: "<<name<<" "<<"advisor: "<<advisor<<endl; }
即希望用基类指针来引用不同的对象(基类的或派 生类的),并能根据引用的对象不同,调用相应的 成员函数(表现出不同的行为)——“多态”。
显然,这里我们未能如愿。
12.3 虚函数
12.3.1 虚函数的作用
C++中的虚函数就是用来解决上节的问题的。 虚函数的作用是允许在派生类中重新定义与 基类同名的函数,并且可以通过基类指针或 引用来访问基类和派生类中的同名函数。
详解C++多态的实现及原理
详解C++多态的实现及原理C++的多态性⽤⼀句话概括就是:在基类的函数前加上virtual关键字,在派⽣类中重写该函数,运⾏时将会根据对象的实际类型来调⽤相应的函数。
如果对象类型是派⽣类,就调⽤派⽣类的函数;如果对象类型是基类,就调⽤基类的函数1:⽤virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数。
2:存在虚函数的类都有⼀个⼀维的虚函数表叫做虚表,类的对象有⼀个指向虚表开始的虚指针。
虚表是和类对应的,虚表指针是和对象对应的。
3:多态性是⼀个接⼝多种实现,是⾯向对象的核⼼,分为类的多态性和函数的多态性。
4:多态⽤虚函数来实现,结合动态绑定.5:纯虚函数是虚函数再加上 = 0;6:抽象类是指包括⾄少⼀个纯虚函数的类。
纯虚函数:virtual void fun()=0;即抽象类!必须在⼦类实现这个函数,即先有名称,没有内容,在派⽣类实现内容。
下⾯看下c++语⾔虚函数实现多态的原理⾃上⼀个帖⼦之间跳过了⼀篇总结性的帖⼦,之后再发,今天主要研究了c++语⾔当中虚函数对多态的实现,感叹于c++设计者的精妙绝伦c++中虚函数表的作⽤主要是实现了多态的机制。
⾸先先解释⼀下多态的概念,多态是c++的特点之⼀,关于多态,简⽽⾔之就是⽤⽗类的指针指向其⼦类的实例,然后通过⽗类的指针调⽤实际⼦类的成员函数,这种⽅法呢,可以让⽗类的指针具有多种形态,也就是说不需要改动很多的代码就可以让⽗类这⼀种指针,⼲⼀些很多⼦类指针的事情,这⾥是从虚函数的实现机制层⾯进⾏研究在写这篇帖⼦之前对于相关的⽂章进⾏了查阅,基本上是⼤段的⽂字,所以我的这⼀篇可能会⽤⼤量的图形进⾏赘述(如果理解有误的地⽅,烦请⼤佬能够指出),接下来就⾔归正传:⾸先介绍⼀下为什么会引进多态呢,基于c++的复⽤性和拓展性⽽⾔,同类的程序模块进⾏⼤量重复,是⼀件⽆法容忍的事情,⽐如我设置了苹果,⾹蕉,西⽠类,现在想把这些东西都装到碗这个函数⾥,那么在主函数当中,声明对象是必须的,但是每⼀次装进碗⾥对于⽔果来说,都要⽤⾃⼰的指针调⽤⼀次装的功能,那为什么不把这些类抽象成⼀个⽔果类呢,直接定义⼀个⽔果类的指针⼀次性调⽤所有⽔果装的功能呢,这个就是利⽤⽗类指针去调⽤⼦类成员,但是这个思想受到了指针指向类型的限制,也就是说表⾯指针指向了⼦类成员,但实际上还是只能调⽤⼦类成员⾥的⽗类成员,这样的思想就变的毫⽆意义了,如果想要解决这个问题,只要在⽗类前加上virtual就可以解决了,这⾥就是利⽤虚函数实现多态的实例。
c++多态实现原理
c++多态实现原理C++多态是面向对象程序设计中的重要概念。
它允许不同类型的对象对同一方法进行不同的操作,这在程序设计中具有很大的灵活性和可维护性。
本文将介绍C++多态的实现原理。
多态的定义多态是指一个对象具有多种形态,它可以根据上下文的不同而表现出不同的行为。
在面向对象程序设计中,多态是指不同类型的对象对同一方法进行不同的操作。
多态性有两种表现形式:静态多态和动态多态。
静态多态是通过函数重载和模板实现的,而动态多态是通过虚函数和继承实现的。
静态多态静态多态是指在编译期确定函数的调用方式。
C++通过函数重载和模板实现了静态多态。
函数重载函数重载是指在同一个作用域内定义多个名称相同但是参数类型和数量不同的函数。
当调用函数时,编译器会根据实参的类型和数量选择最匹配的函数。
如下例所示:```void fun(int x) {// do something}模板模板是C++的一个重要特性,可以使代码在编译时生成。
它可以用来实现函数和类的泛型化,可以接受任意数据类型的参数。
例如,我们可以用下面的代码来定义一个模板函数:```template<typename T>T max(T a, T b) {return a > b ? a : b;}虚函数虚函数是指在基类中声明为虚函数的函数,在派生类中可以被重新定义。
在调用虚函数时,会根据实际对象的类型来调用相应的函数。
例如:```class Animal {public:virtual void make_sound() {std::cout << "Animal makes sound" << std::endl;}};继承继承是指一个派生类可以继承一个或多个基类的数据和函数。
派生类可以重写基类的函数,从而改变基类函数的行为。
例如:class Rectangle : public Shape {public:Rectangle(double w, double h) : width_(w), height_(h) {}double area() const override {return width_ * height_;}private:double width_, height_;};在这个例子中,`Shape`类中定义了一个纯虚函数`area`,派生类`Rectangle`和`Circle`分别继承了`Shape`类。
C 程序设计04章多态性.ppt
4.1 多态性概述
多态性的概念:(polymorphisn) 是指多种表现形式,具体地说,就是把同样的消息发给不同类型的 对象后可能导致完全不同的行为,即“一个对外接口,对应多个内 在实现方法”。多态性连同前面所讲过的封装性和继承性一起,构 成了面向对象程序设计的三大基本特征。 多态性的实现:
Hour=NewH; Minute=NewM; Second=NewS; } void Clock::ShowTime() {
cout<<Hour<<":"<<Minute<<":"<<Second<<endl; }
LanJiming@ copyright Saturday, April 11, 2020 四川理工学院计算机学院 《C++程序设计》 第 10页
LanJiming@ copyright Saturday, April 11, 2020 四川理工学院计算机学院 《C++程序设计》 第 3页
又如:要重载前置单目运算符P为类成员函数,使之能够实现表 达式P oprd的运算,其中假定oprd 为A类的对象,则P就应该被重 载为 A 类的成员函数,没有形参。经重载后,执行表达式P oprd就 相当于执行oprd.operatorU( ) 。
友元概念的引入: 按照封装性的概念,一个类之外的函数只能访问这个类中的 public成员。如果要让这个类之外的函数访问到自己的private或 protected成员,就必须打破原有的封装性,方法就是设定该类的友 元。应该说,友元和封装是一对相反的概念,一个是要“实现开 放”,另一个则是要“限制开放”。 一个类的友元可以是一个普通的函数(即非成员函数)、另一 个类的成员函数或者另一个完整的类。 如何设置一个类的友元呢?在类的定义中使用friend保留字进行 说明,并在friend之后列出友元的名字。如果是把一个完整的类B 作为类A的友元,则类B中所有的成员函数都将被视为类A的友元函 数。
c++多态实现的原理
c++多态实现的原理C++ 中的多态性是通过虚函数(virtual function)和动态绑定(dynamic binding)来实现的。
多态性允许一个基类的指针或引用在运行时引用派生类的对象,从而实现在运行时选择正确的函数实现。
以下是C++ 多态性的基本原理:1. 虚函数(Virtual Function):-在基类中,通过在函数声明前加上`virtual` 关键字,可以将该函数声明为虚函数。
```cppclass Base {public:virtual void myFunction() {// 基类中的虚函数实现}};```2. 派生类的覆盖(Override):-派生类继承基类的虚函数,并可以选择性地覆盖(override)这些函数。
覆盖的函数在派生类中重新定义,但仍然保持`virtual` 关键字。
```cppclass Derived : public Base {public:void myFunction() override {// 派生类中对虚函数的覆盖实现}};```3. 基类指针和引用:-使用基类的指针或引用可以引用派生类的对象。
这是多态性的关键。
```cppBase* ptr = new Derived();ptr->myFunction(); // 运行时会调用Derived类的实现```4. 动态绑定(Dynamic Binding):-当通过基类指针或引用调用虚函数时,实际上是在运行时确定调用的函数版本,而不是在编译时确定。
这称为动态绑定。
```cppBase* ptr = new Derived();ptr->myFunction(); // 动态绑定,调用Derived类的实现```通过使用虚函数和动态绑定,C++ 实现了多态性,使得在运行时能够根据对象的实际类型调用正确的函数版本。
这为构建灵活的、可扩展的代码提供了一种有效的方式。
C++第11章 多态性
第11章 多态性 章
教学内容
11.1多态性概述 11.2 运算符重载 11.3不同类型数据间的转换 11.4虚函数 11.5纯虚函数与抽象类述 多态性概述
多态性是面向对象程序设计的重要特征之一. 多态性是面向对象程序设计的重要特征之一. 是面向对象程序设计的重要特征之一 多态性是指发出同样的消息被 是指发出同样的消息 多态性是指发出同样的消息被不同类型的对象 接收时有可能导致完全不同的行为.利用多态 接收时有可能导致完全不同的行为. 不同的行为 性技术,可以调用同一个函数名的函数 同一个函数名的函数, 性技术,可以调用同一个函数名的函数,实现 完全不同的功能 不同的功能. 完全不同的功能. 多态的实现: 多态的实现:
6
返回目录
11.2运算符重载—什么是运算符重载 运算符重载 什么是运算符重载
运算符重载是对已有的运算符赋予多重含义, 运算符重载是对已有的运算符赋予多重含义, 是对已有的运算符赋予多重含义 同一个运算符作用于不同类型的数据 不同类型的数据导致不同类型 同一个运算符作用于不同类型的数据导致不同类型 的行为. 的行为.C++中预定义的运算符的操作对象只能是 中预定义的运算符的操作对象只能是 基本数据类型.实际上, 基本数据类型.实际上,对于很多用户自定义类型 比如类),也需要有类似的运算操作, ),也需要有类似的运算操作 (比如类),也需要有类似的运算操作,这就提出 了对运算符进行重新定义,赋予已有符号以新的功 了对运算符进行重新定义, 能的要求. 能的要求.
继承关系和虚函数来实现的 来实现的. 继承关系和虚函数来实现的.目的 也是建立一种通用的程序. 也是建立一种通用的程序.通用性 是程序追求的主要目标之一. 是程序追求的主要目标之一.
《深入理解如何在C语言中实现多态》
《深入理解如何在C语言中实现多态》
深入理解如何在C语言中实现多态是一个重要的问题。
多态
是指不同类型的对象能够共享相同的属性和方法,即具有多种形态。
它主要可以用于编写更加灵活,可扩展性强的程序,也可用于优化代码,减少重复性工作。
在C语言中实现多态可以通过函数指针和结构体来实现。
函
数指针是指向一个函数的指针,可以用来实现类型的动态替换。
例如,一个函数指针可以被设置为指向一个int类型的函数,
也可以被设置为指向一个float类型的函数,这样就可以使程
序变得更加灵活。
另外,结构体也可以用来实现多态,因为它可以将不同类型的数据以结构的形式组织在一起,并且可以让不同的数据具有相同的函数。
此外,为了让不同类型的数据具有相同的函数,C语言还提供
了一种特殊的函数类型,即回调函数,也就是指当被调用时,它会自己执行一些代码的函数。
回调函数可以完成对各种不同数据类型的处理,因此也可以实现多态。
总之,C语言中实现多态可以使用函数指针和结构体,还可以
使用回调函数。
它们是C语言中实现多态的主要工具,能够
帮助我们更好地处理复杂的程序,也能更好地优化代码。
只有掌握了这些知识,才能在C语言中更好地实现多态,从而更
好地应对复杂的编程环境。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C++多态性原理
C++多态性
两种表现形式:静态多态性通过一般的函数重载来实现。
动态多态性通过虚函数来实现。
静态多态性比较简单,主要动态多态性比较难理解。
动态多态性有两个条件:
1、在基类中必须使用虚函数、纯虚函数
2、调用函数时要使用基类的指针或引用。
只要在基类的成员函数前加上virtual,该成员函数就是虚函数,从基类派生出来的类的同名成员函数,不管前面是否有virtual,同样是虚函数,在虚函数的实现时,前面不能加virtual。
内联函数不能是虚函数,因为内联函数不能在运行时动态确定位置,即使虚函数在类的内部定义,但在编译的时候仍然看做是非内联的。
只有类的成员函数才能声明为虚函数,普通函数不能声明为虚函数。
静态成员函数不能是虚函数。
虚函数的原理:
普通函数的处理:
一个特定的函数都会映射到特定的代码,无论时编译阶段还是连
接阶段,编译器都能计算出这个函数的地址,调用即可。
虚函数的处理:
被调用的函数不仅依据调用的特定函数,还依据调用的对象的种类。
通常是由虚函数表(vtable)来实现的。
虚函数表的结构:
它是一个函数指针表,每一个表项都指向一个函数。
任何一个包含虚函数的类都会有这样一张表。
需要注意的是vtable只包含虚函数的指针,没有函数体。
实现上是一个函数指针的数组。
虚函数表既有继承性又有多态性
每个派生类的vtable继承了它各个基类的vtable,如果基类vtable 中包含某一项,则其派生类的vtable中也将包含同样的一项,但是两项的值可能不同。
如果派生类重载(override)了该项对应的虚函数,则派生类vtable的该项指向重载后的虚函数,没有重载的话,则沿用基类的值。
每一个类只有唯一的一个vtable,不是每个对象都有一个vtable,每个对象都有一个指针,这个指针指向该类的vtable(当然,前提是这个类包含虚函数)。
那么,每个对象只额外增加了一个指针的大小,一般说来是4字节。
在类对象的内存布局中,首先是该类的vtable指针,然后才是对象数据。
在通过对象指针调用一个虚函数时,编译器生成的代码将先获取对象类的vtable指针,然后调用vtable中对应的项。
对于通过对象指针调用的情况,在编译期间无法确定指针指向的是基类对象还是派生类对象,或者是哪个派生类的对象但是在运行期间执行到调用语句时,这一点已经确定,编译后的调用代码能够根据具体对象获取正确的vtable,调用正确的虚函数,从而实现多态性。
下面是通过基类的指针来调用虚函数时,所发生的一切:
step 1:开始执行调用pA->run();(pA为基类指针,这里能判断到底是哪个对象)
step 2:取得对象的vtable的指针
step 3:从vtable那里获得函数入口的偏移量,即得到要调用的函数的指针
step 4:根据vtable的地址找到函数,并调用函数。
step 1和step 4对于一般函数是一样的,虚函数只是多了step 2和step 3。
基类和派生类是共用一表,还是各有各的表(物理上)?
答:基类和派生类是各有各的表,也就是说他们的物理地址是分开的,基类和派生类的虚表的唯一关联是:当派生类没有实现基类虚函数的重载时,派生类会直接把自己表的该函数地址值写为基类的该函数
地址值.。