成员函数覆盖和重写

函数覆盖:

发生在使用父类指针或引用指向子类对象时:  

  1. 子类对象退化为父类对象

  2. 只能访问父类中定义的成员。

  3. 可以直接访问被子类覆盖的同名成员。

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    void func(int x)
    {}
    void func(int x, int y)
    {}
};

class Child : public Parent
{
public:
    void func(int x, int y, int z)
    {}
};

int main()
{
    Parent p;
    Child c;
    
    p = c;                    // 用子类赋值给父类  
    Parent p1(c);             // 用子类初始化父类
      
    Parent& cite_p = c;       // 父类引用子类    编译器只能根据指针所指向的类型来判断所指向的对象的类型-->也就是Parent
    Parent* point_p = &c;     // 父类指向子类    指针所指向的类型(parent)来判断所指向的对象的类型(parent)
    
    cite_p.add(1);           // 子类退化为父类
    cite_p.add(1,1);          // 子类退化为父类
    cite_P.add(1,1,1)         // error 子类退化为父类,无法引用子类函数

    point_p.add(1);          // 子类退化为父类
    point_p.add(1,1);        // 子类退化为父类
    point_p.add(1,1,1)       // error 子类退化为父类,无法通过指针访问子类函数  
    return 0;
}

函数重写:

  1. 子类中重定义了与父类完全相同的函数。

  2. 重定义发生在继承中时就叫重写。

  3. 函数重写只是一种特殊的同名覆盖(函数名和参数完全相同的覆盖)。

  4. 依旧可以通过作用域分辨符来访问被重写的函数。

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    void print()
    {
        cout << "I'm Parent." << endl;
    }
};

class Child : public Parent
{
public:
    void print()   // 函数重写
    {
        cout << "I'm Child." << endl;
    }
};

void how_to_print(Parent* p)
{
    p->print();
}

int main()
{
    Parent p;
    Child c;
    
    how_to_print(&p);    //  I'm Parent.  退化为父类指针,之可以访问父类的成员函数和成员变量。
    how_to_print(&c);    //  I'm Parent.  退化为父类的指针。函数重写却没有用,原因是指针所指向的类型(parent)来判断所指向的对象的类型(parent)
    c.Parent::print();   //  I'm Parent.  通过作用域访问符来访问被重写的函数
   c.print();           //  I'm Child.   函数覆盖
  return 0; }

Java覆盖是:方法名相同,参数列表相同,返回值相同。

C++覆盖是:方法名相同,       返回值相同。

在Java中出现子类的方法的方法名与父类相同时,会继承父类的同名函数,子类可以访问。

在C++中出现子类的函数的函数名与父类相同时,会覆盖父类的同名函数,子类无法访问。

#include<iostream>

using namespace std;

class Parent
{
public:
    int add(int val1)
    {
        return (val1);
    }
};

class Child : public Parent
{
public:
    int add(int val1, int val2)
    {
        return (val1 + val2);
    }
    
    int add(int val1, int val2, int val3)
    {
        return (val1 + val2 + val3);
    }
};

int main(void)
{
    Child c1;
    Child* c2 = new Child();
    cout << c1.add(1) << endl;   //error 函数同名但参数列表不同会隐藏父类同名函数
    return 0;
}
class Parent
{
    public int add(int val1)
    {
        return (val1);
    }
}

class Child extends Parent
{
    public int add(int val1, int val2)
    {
        return (val1 + val2);
    }
    
    public int add(int val1, int val2, int val3)
    {
        return (val1 + val2 + val3);
    }
}

public class Chapter8_1
{
    public static void main(String[] args)
    {
        Child c = new Child();
        System.out.println(c.add(1));  //ok 同名函数但参数列表不同并不会隐藏
    }

}

由于编译器对指针的处理方式,所以当对重写后的函数进行指针访问时会出错。

父子间的兼容性:

  1. 子类对象可以直接赋值给父类对象:Parent p; Child c; p = c;

  2. 子类对象可以直接初始化父类对象:Parent p(c);

  2. 父类对象可以直接引用子类对象:Parent& p = c;

  3. 父类对象可以直接指向子类对象:Parent* p = &c;

   以上是编译器将子类对象退化为父类对象,从而可以初始化父类。所以以上父类对象(指针,引用)只能访问父类的成员。

问题: 子类可以重写父类的成员,根据兼容性使用父类指针后又无法访问重写的函数。

  可以通过强制转化将父类对象转化为子类对象。

  Child*  c = (static_cast*)<Child*>p;

原文地址:https://www.cnblogs.com/zsy12138/p/10848218.html