C++程序设计POJ》《WEEK6 多态与虚函数》

问题: 虚函数都是同名 同参数表的吗?

虚函数和普通成员函数的区别

虚函数可以多态,其他不行

在构造函数和析构函数中调用 虚函数 不是多态

派生类还没有初始化好

MyCompare()

qsort 怎么表示排序关系

虚函数表地址!!

虚函数
?
在类的定义中,前面有 virtual 关键字的成员
函数就是虚函数。
class base{

virtual   int get() };

int base::get()
{ }

virtual 关键字只用在类定义里的函数声明中,
写函数体时不用。
多态的表现形式一

?
派生类的指针可以赋给基类指针。
?
通过基类指针调用基类和派生类中的同名 虚函数 时

1 )若该指针指向一个基类的对象,那么被调用
是基类的 虚函数

2 )若该指针指向一个派生类的对象,那么被调
用的是派生类的 虚函数 。
这种机制就叫做“
多态 ”。

class CBase {
public:
virtual  void SomeVirtualFunction() { }
};
class CDerived:public CBase {
public :
virtual  void SomeVirtualFunction() { }
};
int main() {
CDerived ODerived;
CBase * p = & ODerived;
p-> SomeVirtualFunction(); // 调用哪个虚函数取决于 p 指向哪种类型的对象  调用CDerived类的虚函数
return 0;
}

多态的表现形式二
?
派生类的对象可以赋给基类引用
?
通过基类引用调用基类和派生类中的同名 虚函数 时

1 )若该引用引用的是一个基类的对象,那么被
调用是基类的 虚函数

2 )若该引用引用的是一个派生类的对象,那么
被调用的是派生类的 虚函数 。
这种机制也叫做“
多态 ”。

class CBase {
public:
virtual
void SomeVirtualFunction() { }
};
class CDerived:public CBase {
public :
virtual
void SomeVirtualFunction() { }
};
int main() {
CDerived ODerived;
CBase & r = ODerived;
r.SomeVirtualFunction(); //调用哪个虚函数取决于 r 引用哪种类型的对象
return 0;
}

多态的作用

在面向对象的程序设计中使用多态,能够增强
程序的 可扩充性 ,即程序需要修改或增加功能
的时候,需要改动和增加的代码较少。

/*
几何形体处理程序
Sample Input:
3
R 3 5
C 9
T 3 4 5
Sample Output
Triangle:6
Rectangle:15
Circle:254.34
39
*/
#include<iostream>
#include<stdlib.h>
#include<math.h>

using namespace std;
class CShape
{
public:
    virtual double Area() = 0; // 纯虚函数
    virtual void PrintInfo() = 0;
};

class CRectangle :public CShape
{
public:
    int w, h;
    virtual double Area();
    virtual void PrintInfo();
};
class CCircle :public CShape
{
public:
    int r;
    virtual double Area();
    virtual void PrintInfo();

};
class CTriangle :public CShape
{
public:
    int a, b, c;
    virtual double Area();
    virtual void PrintInfo();
};
double CRectangle::Area()
{
    return w*h;
}
void CRectangle::PrintInfo()
{
    cout << "rectanlgle:" << Area() << endl;
}

double CCircle::Area()
{
    return 3.14*r*r;
}
void CCircle::PrintInfo()
{
    cout << "circle:" << Area() << endl;
}
double CTriangle::Area()
{
    double p = (a + b + c) / 2.0;
    return sqrt(p*(p - a)*(p - b)*(p - c));
}
void CTriangle::PrintInfo()
{
    cout << "triangle:" << Area() << endl;
}

CShape * pShapes[100]; // 基类 指针数组
int MyCompare(const void *s1, const void *s2);

int MyCompare(const void* s1, const void *s2)
{
    double a1, a2;
    CShape** p1; // s1,s2 是 void * ,不可写 ““* s1 ”来取得 s1 指向的内容
    CShape** p2;
    p1 = (CShape**)s1;//s1,s2 指向 pShapes 数组中的元素,数组元素的类型是 CShape *
    p2 = (CShape**)s2;// 故 p1,p2 都是指向指针的指针,类型为 CShape **
    a1 = (*p1)->Area();// * p1 的类型是 Cshape * , 是基类指针,故此句为多态
    a2 = (*p2)->Area();
    if (a1 < a2)
        return -1;
    else if (a2 < a1)
        return 1;
    else
        return 0;
}
int main()
{
    int i, n;
    CRectangle *pr;
    CCircle *pc;
    CTriangle *pt;
    cin >> n;
    for (i = 0; i < n; i++)
    {
        char c;
        cin >> c;
        switch (c)
        {
        case ‘R‘:
            pr = new CRectangle();
            cin >> pr->w >> pr->h;
            pShapes[i] = pr; // 派生类指针 赋给 基类
            break;
        case ‘C‘:
            pc = new CCircle;
            cin >> pc->r;
            pShapes[i] = pc;
            break;
        case ‘T‘:
            pt = new CTriangle();
            cin >> pt->a >> pt->b >> pt->c;
            pShapes[i] = pt;
            break;

        }
    }

    qsort(pShapes, n, sizeof(CShape*), MyCompare);
    for (i = 0; i < n; i++)
        pShapes[i]->PrintInfo();
    while (1);
    return 0;
}

用基类指针数组存放指向各种派生类对象的指
针,然后遍历该数组,就能对各个派生类对象
做各种操作,是很常用的做法

构造函数和析构函数中调用虚函数

在构造函数和析构函数中调用虚函数,不是多态。编
译时即可确定,调用的函数是 自己的类或基类 中定义
的函数,不会等到运行时才决定调用自己的还是派生
类的函数。

派生类中和基类中虚函数同名同参数表的函数,不加
virtual 也自动成为虚函数

class myclass
public:
virtual void hello(){cout<<"hello from myclass"<<endl; };
virtual void bye(){cout<<"bye from myclass"<<endl;}
};
class son:public myclass
{
void hello(){ cout<<"hello from son"<<endl;};
son(){ hello();}
~son(){bye(); };
class grandson:public son
{
void hello(){cout<<"hello from grandson"<<endl;};
void bye() { cout << "bye from grandson"<<endl;}
grandson(){cout<<"constructing grandson"<<endl;};
~grandson(){cout<<"destructing grandson"<<endl;};
};
int main(){
grandson gson;
son *pson;
pson=&gson;
pson->hello(); 多态
return 0;
}
/*
结果:
hello from son
constructing grandson
hello from grandson
destructing grandson
bye from myclass

*/

虚函数的访问权限

class Base {
private:
virtual void fun2() { cout << "Base::fun2()" << endl; }
};
class Derived:public Base {
public:
virtual void fun2() { cout << "Derived:fun2()" << endl; }
};
Derived d;
Base * pBase = & d;
pBase-> fun2(); // 编译出错

编译出错是因为 fun2() 是 Base 的私有成员。即使运行到此时实际上调用的应该是
Derived 的公有成员 fun2() 也不行,因为语法检查是不考虑运行结果的。
?
如果 将 Base 中的 private 换成 public, 即使 Derived 中的 fun2() 是 private 的,编译依然能通
过,也能正确调用 Derived::fun2() 。

#include<iostream>
using namespace std;
class Base
{
public:
    virtual void fun2()
    {
        cout << "base::fun2()" << endl;
    }
};
class Derived :public Base
{
private:
    virtual void fun2()
    {
        cout << "Derived:fun2()" << endl;
    }
};

int main()
{
    Derived d;
    Base * pBase = &d;
    pBase->fun2(); // 神奇了,private也能访问!!!
    while (1);
    return 0;

}

原文地址:https://www.cnblogs.com/focus-z/p/11074587.html

时间: 2024-11-05 19:52:33

C++程序设计POJ》《WEEK6 多态与虚函数》的相关文章

C++程序设计POJ》《WEEK6 多态与虚函数》《多态的实现原理》《虚函数表》

“多态”的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定---- 这叫“动态联编”.“动态联编” 底是怎么实现的呢? #include<iostream> using namespace std; class Base { public: int i; virtual void Print() { cout << "base:print"; } }; class Derived :public Base {

C++程序设计POJ》《WEEK6 多态与虚函数》《编程填空》

#include <iostream> using namespace std; class A { public: A() { } virtual void func() { cout << "A::func" << endl; } virtual void fund() { cout << "A::fund" << endl; } void fun() { cout << "A::

PKU C++程序设计实习 学习笔记3 多态与虚函数

第六章 多态与虚函数 6.1 多态和虚函数的基本概念 引言 多态是面向对象程序设计里面非常重要的这个机制.它能很有效的提高程序的可扩充性. 有些程序设计语言有被对象继承的概念,但是没有多态的概念,那这样的程序设计语言只能被称作基于对象的程序设计语言,而不能称为面向对象的语言, 比方说visual basic. 虚函数 在类的定义中,前面有 virtual 关键字的成员函数就是虚函数. class base { <span style="color:#ff0000;">vir

GeekBand-secondweek-c++的多态和虚函数

多态与虚函数 13章的简单继承只是实现了对已有对象的实现的重定义和直接调用,但是向上映射导致的对象切割仍然是个缺陷: 1.延续13章的向上映射 简单继承中,派生类重定义了基类的成员函数,此时,向上映射的结果是很明显的,它使用了基类实现的函数版本,这显然并不是我们想要的效果:为什么会有这样的结果发生,我们先探讨几个问题: 函数调用绑定:函数调用确定目标函数体称为捆绑,编译期绑定称为早绑定,上面的问题就是早绑定引起的,因为编译器只知道基类对象的类型,调用函数也会绑定基类实现的函数版本,要解决这一问题

C++中的多态与虚函数的内部实现

1.什么是多态 多态性可以简单概括为“一个接口,多种方法”. 也就是说,向不同的对象发送同一个消息, 不同的对象在接收时会产生不同的行为(即方法).也就是说,每个对象可以用自己的方式去响应共同的消息.所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数.这是一种泛型技术,即用相同的代码实现不同的动作.这体现了面向对象编程的优越性. 多态分为两种: (1)编译时多态:主要通过函数的重载和运算符的重载来实现. (2)运行时多态:主要通过虚函数来实现. 2.几个相关概念 (1)覆盖.重

C++的多态与虚函数

多态性:对于同一消息,不同的对象由不同的响应方式 多态分为静态多态(编译时多态)和动态多态(运行时多态),动态多态通过虚函数来实现. 覆盖-->子类和父类中有同名同参数列表但是功能不同的函数叫做覆盖,在同一个类中有相同的是重复定义,不是覆盖. 虚函数的使用方法,如下: ①在基类中声明一个函数为虚函数,如: //基类vStudent class vStudent { public: vStudent(int,string); virtual void display();//虚函数,用来实现多态性

多态实现--虚函数与纯虚函数

多态实现--虚函数与纯虚函数 C++中实现多态是使用虚函数表的方法实现的. 那么具体怎么实现的呢? 举例说明 假设有这样一个多态场景: 有一个基类动物(animal类),动物里面又有两个派生类:猫(cat类)和狗(dog类).现在要求动物类有一个共同的方法:叫声(voice成员函数),但猫和狗叫声是不同的(即:它们的叫声实现方法不同). 那么代码怎么写呢? 多态的代码实现 #include <iostream> using namespace std; //1. 定义一个纯虚函数 class

C++ 多态与虚函数

1.多态的概念 由虚函数实现的动态多态性就是:同一类族中不同类的对象,对同一函数调用作出不同的响应. 先看下面这个简单的例子: #include<iostream> using std::cout; using std::endl; class A { public: void print(){cout << "I am A's print" << endl;} }; class B : public A { public: void print()

《C++编程思想》 第十四章 多态和虚函数 (原书代码+习题+讲解)

一.相关知识点 函数调用捆绑 把函数体与函数调用相联系称为捆绑(binding).当捆绑在程序运行之前(由编译器和连接器)完成时,称为早捆绑.我们可能没有听到过这个术语,因为在过程语言中是不会有的:C编译只有一种函数调用,就是早捆绑.上面程序中的问题是早捆绑引起的,因为编译器在只有 instrument地址时它不知道正确的调用函数.解决方法被称为晚捆绑,这意味着捆绑在运行时发生,基于对象的类型.晚捆绑又称为动态捆绑或运行时捆绑.当一个语言实现晚捆绑时,必须有一种机制在运行时确定对象的类型和合适的