C++中继承与多态

2017-10-14  本文已影响0人  nethanhan

父子间的同名冲突

首先来看一段代码:

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    int mi;
};

class Child : public Parent
{
public:
    int mi;
};

int main()
{
    Child c;
    
    //这里的mi是Parent中的还是Child中的呢?
    c.mi = 100;
    
    return 0;
}

编译通过,说明子类可以定义和父类相同的同名成员。

Child c;

//子类中的mi
c.mi = 100;

//父类中的mi
c.Parent::mi = 1000;

再来看一个例子:

#include <iostream>
#include <string>

using namespace std;

//定义一个命名空间A
namespace A
{
    int g_i = 0;
}
//定义一个命名空间B
namespace B
{
    int g_i = 1;
}

class Parent
{
public:
    int mi;
    
    Parent()
    {
        cout << "Parent() : " << "&mi = " << &mi << endl;
    }
};

class Child : public Parent
{
public:
    int mi;
    
    Child()
    {
        cout << "Child() : " << "&mi = " << &mi << endl;
    }
};

int main()
{
    Child c;
    
    //向子类的mi成员赋值100
    c.mi = 100;    
    //通过作用域向父类的mi成员赋值1000
    c.Parent::mi = 1000;
    
    //打印子类中mi的地址
    cout << "&c.mi = " << &c.mi << endl;
    //打印子类中mi的内容
    cout << "c.mi = " << c.mi << endl;
    
    //打印父类中mi的地址
    cout << "&c.Parent::mi = " << &c.Parent::mi << endl;
    //打印父类中mi的内容
    cout << "c.Parent::mi = " << c.Parent::mi << endl;
    
    return 0;
}

输出结果为:

Parent() : &mi = 0x7fff57f57a90
Child() : &mi = 0x7fff57f57a94
&c.mi = 0x7fff57f57a94
c.mi = 100
&c.Parent::mi = 0x7fff57f57a90
c.Parent::mi = 1000

比如像这样:

class Parent
{
public:
    int mi;
    
    void add(int v)
    {
        mi += v;
    }
    
    void add(int a, int b)
    {
        mi += (a + b);
    }
};

class Child : public Parent
{
public:
    int mi;
    
    void add(int v)
    {
        mi += v;
    }
    
    void add(int a, int b)
    {
        mi += (a + b);
    }
    
    void add(int x, int y, int z)
    {
        mi += (x + y + z);
    }
};

代码 Parent类 和 Child类 中有同名的函数add ,但是两个类之间不构成重载,只有Parent类中多个add函数构成重载。

父子间的赋值兼容

举个例子:

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    int mi;
    
    void add(int i)
    {
        mi += i;
    }
    
    void add(int a, int b)
    {
        mi += (a + b);
    }
};

class Child : public Parent
{
public:
    int mv;
    
    void add(int x, int y, int z)
    {
        mv += (x + y + z);
    }
};

int main()
{
    Parent p;
    Child c;
    //子类对象可以直接赋值给父类对象
    p = c;
    //子类对象可以直接初始化父类对象
    Parent p1(c);
    //父类引用可以直接引用子类对象
    Parent& rp = c;
    //父类指针可以直接指向子类对象
    Parent* pp = &c;

    return 0;
}

在main函数中进行上述几条的操作都没有出现编译出错。现在进行这样操作:

rp.mi = 100;
rp.add(5);        
rp.add(10, 10);  

发现可以编译通过,并没有出现同名覆盖的问题。但是如果这样操作:

pp->mv = 1000;
pp->add(1, 10, 100);

运行以后就会报错,报错信息如下:

48-1.cpp:51:10: error: no member named 'mv' in 'Parent'
     pp->mv = 1000;
     ~~  ^
48-1.cpp:52:10: error: no matching member function for call to 'add'
     pp->add(1, 10, 100);
     ~~~~^~~
48-1.cpp:16:10: note: candidate function not viable: requires 2 arguments, but 3
      were provided
    void add(int a, int b)
         ^
48-1.cpp:11:10: note: candidate function not viable: requires single argument
      'i', but 3 arguments were provided
    void add(int i)
         ^
2 errors generated.

信息提示没有找到带有3个参数的add函数。为什么呢?

特殊的同名函数

例如:

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

//函数重写

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

假如函数重写和赋值兼容同时出现呢? 就像这样:

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    int mi;
    
    void add(int i)
    {
        mi += i;
    }
    
    void add(int a, int b)
    {
        mi += (a + b);
    }
    
    void print()
    {
        cout << "I'm Parent." << endl;
    }
};

class Child : public Parent
{
public:
    int mv;
    
    void add(int x, int y, int z)
    {
        mv += (x + y + z);
    }
    
    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);    // Expected to print: I'm Parent.
    how_to_print(&c);    // Expected to print: I'm Child.
    
    return 0;
}

预期输出是 I'm Parent.I'm Child. 。但是实际输出:

I'm Parent.
I'm Parent.

在编译 void how_to_print(Parent* p) 这个函数时,编译器不可能知道指针p究竟指向了什么,但是编译器没有理由报错。于是,编译器认为最安全的做法是调用父类的print函数,因为父类和子类肯定都有相同的print函数。

多态的概念和意义

就像这样:

Child c;
Parent* p = &c;

c.Parent::print();  //从父类中继承
c.print();          //从子类中重写

p->print();         //父类中定义

虽然程序逻辑是这样,但并不是我们所期望的。面向对象中期望的行为:

这里就引出了面向对象中的 多态 的概念:

例如:

p->print();

p指向父类对象时,会执行

void print()
{
    cout << "I'm Parent" << end;
}

p指向子类对象时,会执行

void print()
{
    cout << "I'm Child" << endl;
}

举个例子:

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    //用 virtual 关键字修饰,则具有多态特性
    virtual 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);    // Expected to print: I'm Parent.
    how_to_print(&c);    // Expected to print: I'm Child.
    
    return 0;
}

执行结果为:

I'm Parent.
I'm Child.

静态联编和动态联编

举个例子:

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    //函数重载  并且用 virtual 关键字修饰
    virtual void func()
    {
        cout << "void func()" << endl;
    }
    //函数重载  并且用 virtual 关键字修饰
    virtual void func(int i)
    {
        cout << "void func(int i) : " << i << endl;
    }
    //函数重载  并且用 virtual 关键字修饰
    virtual void func(int i, int j)
    {
        cout << "void func(int i, int j) : " << "(" << i << ", " << j << ")" << endl;
    }
};

class Child : public Parent
{
public:
    //函数重载
    void func(int i, int j)
    {
        cout << "void func(int i, int j) : " << i + j << endl;
    }
    //函数重载
    void func(int i, int j, int k)
    {
        cout << "void func(int i, int j, int k) : " << i + j + k << endl;
    }
};

void run(Parent* p)
{
    p->func(1, 2);     // 展现多态的特性
                       // 动态联编
}

int main()
{
    Parent p;
    
    p.func();         // 静态联编
    p.func(1);        // 静态联编
    p.func(1, 2);     // 静态联编
    
    cout << endl;
    
    Child c;
    
    c.func(1, 2);     // 静态联编
    
    cout << endl;
    
    run(&p);
    run(&c);
    
    return 0;
}

运行结果为:

void func()
void func(int i) : 1
void func(int i, int j) : (1, 2)

void func(int i, int j) : 3

void func(int i, int j) : (1, 2)
void func(int i, int j) : 3

小结

上一篇 下一篇

猜你喜欢

热点阅读