0.目录

1.同名覆盖

2.赋值兼容

3.函数重写遇上赋值兼容

4.小结

1.同名覆盖

子类中是否可以定义父类中的同名成员?如果可以,如何区分?如果不可以,为什么?

父子间的冲突:

  • 子类可以定义父类中的同名成员
  • 子类中的成员将隐藏父类中的同名成员
  • 父类中的同名成员依然存在于子类中
  • 通过作用域分辨符( :: )访问父类中的同名成员

访问父类中的同名成员:

示例:

#include <iostream>

using namespace std;

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; c.mi = 100; c.Parent::mi = 1000; cout << "&c.mi = " << &c.mi << endl;
cout << "c.mi = " << c.mi << endl; cout << "&c.Parent::mi = " << &c.Parent::mi << endl;
cout << "c.Parent::mi = " << c.Parent::mi << endl; return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
Parent() : &mi = 0x7ffe251260c0
Child() : &mi = 0x7ffe251260c4
&c.mi = 0x7ffe251260c4
c.mi = 100
&c.Parent::mi = 0x7ffe251260c0
c.Parent::mi = 1000

类中的成员函数可以进行重载:

  1. 重载函数的本质为多个不同的函数
  2. 函数名参数列表是唯一的标识
  3. 函数重载必须发生在同一个作用域中

子类中定义的函数是否能重载父类中的同名函数?

示例:

#include <iostream>

using namespace std;

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);
}
}; int main()
{
Child c; c.mi = 100; c.Parent::mi = 1000; cout << "c.mi = " << c.mi << endl; cout << "c.Parent::mi = " << c.Parent::mi << endl; c.add(1);
c.add(2, 3);
c.add(4, 5, 6); cout << "c.mi = " << c.mi << endl; cout << "c.Parent::mi = " << c.Parent::mi << endl; return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
c.mi = 100
c.Parent::mi = 1000
c.mi = 121
c.Parent::mi = 1000

父子间的冲突:

  • 子类中的函数将隐藏父类的同名函数
  • 子类无法重载父类中的成员函数
  • 使用作用域分辨符访问父类中的同名函数
  • 子类可以定义父类中完全相同的成员函数

示例:

#include <iostream>

using namespace std;

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 x, int y, int z)
{
mi += (x + y + z);
}
}; int main()
{
Child c; c.mi = 100; c.Parent::mi = 1000; cout << "c.mi = " << c.mi << endl; cout << "c.Parent::mi = " << c.Parent::mi << endl; c.Parent::add(1);
c.Parent::add(2, 3);
c.add(4, 5, 6); cout << "c.mi = " << c.mi << endl; cout << "c.Parent::mi = " << c.Parent::mi << endl; return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
c.mi = 100
c.Parent::mi = 1000
c.mi = 115
c.Parent::mi = 1006

2.赋值兼容

子类对象可以当作父类对象使用(兼容性):

  • 子类对象可以直接赋值给父类对象
  • 子类对象可以直接初始化父类对象
  • 父类指针可以直接指向子类对象
  • 父类引用可以直接引用子类对象

示例——能编译通过的赋值兼容:

#include <iostream>

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; // 第1种兼容性 Parent p1(c); // 第2种兼容性
Parent& rp = c; // 第3种兼容性
Parent* pp = &c; // 第4种兼容性 rp.mi = 100;
rp.add(5); // 没有发生同名覆盖?
rp.add(10, 10); // 没有发生同名覆盖? return 0;
}

当使用父类指针(引用)指向子类对象时:

  • 子类对象退化为父类对象
  • 只能访问父类中定义的成员
  • 可以直接访问被子类覆盖的同名成员

3.函数重写遇上赋值兼容

特殊的同名函数:

  • 子类中可以重定义父类中已经存在的成员函数
  • 这种重定义发生在继承中,叫做函数重写
  • 函数重写是同名覆盖的一种特殊情况

当函数重写遇上赋值兼容会发生什么?

示例——函数重写遇上赋值兼容:

#include <iostream>

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;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
I'm Parent.
I'm Parent.

问题分析:

  • 编译期间,编译器只能根据指针的类型判断所指向的对象
  • 根据赋值兼容,编译器认为父类指针指向的是父类对象
  • 因此,编译结果只可能是调用父类中定义的同名函数



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

4.小结

  • 子类可以定义父类中的同名成员
  • 子类中的成员将隐藏父类中的同名成员
  • 子类和父类中的函数不能构成重载关系
  • 子类可以定义父类中完全相同的成员函数
  • 使用作用域分辨符访问父类中的同名成员
  • 子类对象可以当作父类对象使用(赋值兼容)
  • 父类指针可以正确的指向子类对象
  • 父类引用可以正确的代表子类对象
  • 子类中可以重写父类中的成员函数

最新文章

  1. Uri各个属性取值测试
  2. EKF的理解
  3. 网页中插入swf动画(embed)
  4. 【转】从Go、Swift语言出发
  5. paper 75:使用MATLAB的神经网络工具箱创建神经网络
  6. C#加密解密算法汇总(转)
  7. 1199: [HNOI2005]汤姆的游戏 - BZOJ
  8. Codeforces 460 DE 两道题
  9. Aps.net中基于bootstrapt图片上传插件的应用
  10. 折腾Java设计模式之模板方法模式
  11. json转换导致金额失真问题解决
  12. [HDU2065] &quot;红色病毒&quot;问题
  13. Ultra-QuickSort POJ - 2299 (逆序对)
  14. XCode各种问题
  15. [redis] &lt;&lt;The little Redis book&gt;&gt;的读书笔记
  16. [02] Spring主要功能模块概述
  17. 从字符集发展史看Unicode和UTF-8的区别
  18. LeetCode OJ 77. Combinations
  19. 编译原理之正则表达式转NFA
  20. 远程连接mysql root账号报错:2003-can&#39;t connect to MYSQL serve(转)

热门文章

  1. sql语句-8-sql学习流程
  2. 【LG3973】[TJOI2015]线性代数
  3. Linux权限管理命令
  4. 接口自动化&#183;分享&#183;第二篇&#183;你必须了解的HttpRequest和HttpResponse
  5. 微信小程序和微信H5测试中易出Bug的点和注意事项
  6. Lua学习笔记(6): 函数
  7. python数据可视化——matplotlib 用户手册入门:使用指南
  8. CSP201612-2:工资计算
  9. Select 、Poll 和 Epoll
  10. Nginx特性验证-反向代理/负载均衡/页面缓存/URL重定向