C++如何确定:该调用基类的虚函数,还是派生类的?

1.直接通过对象来调用:看该对象是谁(基类/派生类)的对象,是谁的对象,就调用谁的函数;

2.通过指针/引用来调用:根据指针/引用“指向的对象”的类型,决定调用谁的函数;

Base *p = new Base();//指针指向“基类对象”,所以会调用 “基类的函数”

Base *p = new Son();//指针指向“派生类对象”,所以会调用 “派生类的函数”

举例说明:

#include "stdafx.h"
#include <iostream>

using namespace std;

class myclass
{
public:
    int i;
    virtual void go()
    {
        i = 0;
        show();
    }
    void show()
    {
        std::cout << "myclass->show()" << std::endl;
    }
    virtual ~myclass()
    {
        // 不加virtual 会造成内存泄漏
    }
};
class newmyclass: public myclass
{
public:
    void go() //子类重写/覆盖父类的虚函数(带不带virtual,都一样,都是虚函数!)
    {
        std::cout << "newmyclass->go()" << std::endl;
    }
    void show()
    {
        std::cout << "newmyclass->show()" << std::endl;
    }
    void put()
    {
        std::cout << "newmyclass->put()" << std::endl;
    }
};

// 1: 指针
void test1(myclass *p)//参数:父类类型指针
{
    p->go();
}

// 2: 引用
void test2(myclass &p)//参数:父类类型引用
{
    p.go();
}

// 3: 对象
void test3(myclass my)//参数:父类对象
{
    my.go();
}

int main()
{
    //1.使用对象调用
    //my是类myclass的一个实例对象,而不是指向类myclass的对象的指针或引用,
    //所以函数调用my.go()是实调用,函数的入口地址是在编译阶段静态决定的
    myclass my;
    my.go();    // 正常调用父类的go函数

    newmyclass newmy;
    newmy.go(); // 正常调用子类的go函数

    //2.使用指针调用
   //myclass *pmy(nullptr);//父类指针
    myclass *pmy(NULL);
    pmy->show(); // 空指针可以调用show操作
    //pmy->go(); // 空指针无法调用go函数,因为myclass类,没有实例化为对象,go函数内部操作了对象的内部变量,此时该内部变量并没有构造出来

    myclass *p = new newmyclass;//创建的是“子类对象”
    p->go();          //调用子类的go函数
    p->myclass::go(); // 指定调用父类的go函数
    std::cout << typeid(p).name() << std::endl; //p的类型为父类类型指针 class myclass *
    std::cout << typeid(*p).name() << std::endl; //*p的类型为子类类型 class newmyclass

    //1.使用指针调用:根据指针对象指向的对象的类型决定
    test1(p); // 调用子类的go函数 (形参指针指向:p指针指向 子类对象)
    test1(&my); // 调用父类的go函数 (形参指针指向:my是父类对象)
    test1(&newmy); // 调用子类的go函数(形参指针指向:newmy是子类对象)

    //2.使用引用调用:根据引用对象引用的对象的类型决定
    // 引用在语言内部用指针实现,引用是操作受限了的指针(仅容许取内容操作)
    test2(*p);  // 调用子类的go函数(形参引用:*p是子类对象)
    test2(my); // 调用父类的go函数 (形参引用:my是父类对象)
    test2(newmy); // 调用子类的go函数(形参引用:newmy是子类对象)

    //3.使用对象调用:谁的对象,就调用谁的函数
    // 对象作为参数,会使用拷贝构造函数,形成对象的副本
    test3(*p);          // 调用父类的go函数 (形参对象:是父类对象)
    test3(my);        // 调用父类的go函数 (形参对象:是父类对象)
    test3(newmy);  // 调用父类的go函数 (形参对象:是父类对象)

    //std::cout << "mytest" << std::endl;
    system("pause");
    return 0;
}

/*
myclass->show()
newmyclass->go()

myclass->show()
newmyclass->go()
myclass->show()

class myclass *
class newmyclass


newmyclass->go()
myclass->show()
newmyclass->go()

newmyclass->go()
myclass->show()
newmyclass->go()

myclass->show()
myclass->show()
myclass->show()
*/

//==================================================

二、如果不是虚函数调用,而是基类和派生类中2个一样函数 的调用

1.直接通过对象来调用:看该对象是谁(基类/派生类)的对象,是谁的对象,就调用谁的函数;

2.通过指针/引用来调用:根据指针/引用的类型,决定调用谁的函数;

Base *p = new Base();//指针类型是Base,所以会调用 “基类的函数”

Base *p = new Son();//指针类型是Base,所以会调用 “基类的函数”

举例说明:

1、

#include "stdafx.h"
#include <stdlib.h>
#include <iostream>
using namespace std;

class A{
public:
    void print(){ cout<<"This is A"<<endl;}
};
class B: public A{
public:
    void print(){ cout<<"This is B"<<endl;}
};

int main(){
    A a;  B b;

    A* p1=&a;
    A* p2=&b;

    p1->print();//This is A
    p2->print();//This is A

    system("pause");
    return 0;
}

2、如果是虚函数

#include "stdafx.h"
#include <stdlib.h>
#include <iostream>
using namespace std;

class A{
public:
    virtual void print(){ cout<<"This is A"<<endl;}
};
class B: public A{
public:
    void print(){ cout<<"This is B"<<endl;}
};

int main(){
    A a;  B b;

    A* p1=&a;
    A* p2=&b;

    p1->print();//This is A
    p2->print();//This is B

    system("pause");
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值