重载,重定义,重写(覆盖),名字隐藏
2016-09-21 10:47
183 查看
主要有三种关系:重载(overload),覆盖(重写)(override),隐藏(重定义)(hide,oversee)
一、重载(overload)-水平关系
指函数名相同,但是它的参数表列个数或顺序,类型不同。但是不能靠返回类型来判断。
(1)相同的范围(在同一个类中) ;
(2)函数名字相同;
(3)参数列表不同;
(4)virtual 关键字可有可无。
(5)返回值可以不同;
二、重写(也称为覆盖 override)-垂直关系
是指派生类重新定义基类的同名虚函数,特征是:
(1)不在同一个作用域(分别位于派生类与基类) ;
(2)基类函数必须有 virtual 关键字,不能有 static 。
(3)与基类虚函数参数类型相同;
(4)与基类虚函数参数个数相同;
(5)与基类虚函数返回值相同(或是协变),否则报错;<—-协变这个概念我也是第一次才知道…
(6)重写函数的访问修饰符可以不同。尽管 virtual 是 private 的,派生类中重写改写为 public,protected 也是可以的
三、重定义(也成隐藏)
(1)不在同一个作用域(分别位于派生类与基类) ;
(2)函数名字相同;
(3)返回值可以不同;
(4)参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载以及覆盖混淆) 。
(5)参数相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) 。
下面通过实际的例子来看看具体的调用情况,同时可以用gdb看看运行的内存地址分布
输出结果:
48
————–find virtual tables test:————-
B::void g()
B::void f()
B::virtual g(int a,int b)
—————-A multi situation test:—————
A::void lambda(int a,int b) called:5
A::int lambda(long long a,long long b) called:
B::void g()
B::void f()
———————–B’s f virtual func:————–
B::void lambda()
B::int lambda(int a,int b)
B::void f()
B::void g()
B::virtual g(int a,int b)
————————-A’s func test:——————
A::virtual void f() called
A::void lambda(int a,int b) called:13
数据成员地址为:
(gdb) p &b
8 = (B *) 0x7fffffffe530
(gdb) p &b.oo9 = (int *) 0x7fffffffe538
(gdb) p &b.p
10 = 0x7fffffffe53c “”
(gdb) p &b.pp11 = (int *) 0x7fffffffe540
(gdb) p &b.a
12 = (long long *) 0x7fffffffe548
(gdb) p &b.d13 = 0x7fffffffe550 “”
(gdb) p &b.q
$14 = (long long *) 0x7fffffffe558
一、重载(overload)-水平关系
指函数名相同,但是它的参数表列个数或顺序,类型不同。但是不能靠返回类型来判断。
(1)相同的范围(在同一个类中) ;
(2)函数名字相同;
(3)参数列表不同;
(4)virtual 关键字可有可无。
(5)返回值可以不同;
二、重写(也称为覆盖 override)-垂直关系
是指派生类重新定义基类的同名虚函数,特征是:
(1)不在同一个作用域(分别位于派生类与基类) ;
(2)基类函数必须有 virtual 关键字,不能有 static 。
(3)与基类虚函数参数类型相同;
(4)与基类虚函数参数个数相同;
(5)与基类虚函数返回值相同(或是协变),否则报错;<—-协变这个概念我也是第一次才知道…
(6)重写函数的访问修饰符可以不同。尽管 virtual 是 private 的,派生类中重写改写为 public,protected 也是可以的
三、重定义(也成隐藏)
(1)不在同一个作用域(分别位于派生类与基类) ;
(2)函数名字相同;
(3)返回值可以不同;
(4)参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载以及覆盖混淆) 。
(5)参数相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) 。
下面通过实际的例子来看看具体的调用情况,同时可以用gdb看看运行的内存地址分布
#include <iostream> using namespace std; class A { public: int oo; char p; int pp; long long q; char a; public: virtual void g() { cout << "A::virtual void g() called" << endl; } virtual void f() { cout << "A::virtual void f() called" << endl; } /* void f() { cout<<"A::void f() called"<<endl; } */ void lambda() { cout << " A::void lambda() called:" << endl; } //同一个类,通过参数列表不同,重载了lambda() //如果定义virtual void lambda(int a,int b),由于子类有不同的返回值,将产生重写overriding失败 void lambda(int a,int b) { cout<<"A::void lambda(int a,int b) called:"<<a+b<<endl; } //同一个类,通过返回值不同,重载了lambda() int lambda(long long a,long long b) { cout<<"A::int lambda(long long a,long long b) called:"<<endl; return a>b; } }; class B : public A { public: //char c; long long d; public: //不同类,注意基类g()有virtual关键字,且参数一致,故称之为重写或者覆盖 void g() { cout << "B::void g()" << endl; } //不同类,基类有virtual关键字,同理,属于重写或覆盖 //同一类,同名函数,参数列表一致,只是加了virtual关键字,怎么算?算重载错误,overload不允许,也是说同一个类不能拿有没有virtual关键字进行重载 /* virtual void g() { cout << "B::virtual void g()" << endl; }*/ //不同类中,基类g函数为虚函数,函数g改变了参数列表,不是重写或者覆盖,那就是属于重定义 //同一类中,利用参数列表不同重载了g virtual void g(int a,int b){ cout << "B::virtual g(int a,int b)" << endl; } //基类f为虚函数,不同类中参数列表一致,重写(覆盖)了f void f() { cout<<"B::void f()"<<endl; } //不同类中,基类lambda为普通函数,参数列表相同,隐藏或者说重定义了基类的lambda void lambda() { cout << "B::void lambda()"<<endl; } //不同类中,基类lambda为普通函数,参数列表一致,返回值不同,重定义了lambda,属于重写?no,只有基类为virtual才算重写,不然归类为重定义 int lambda(int a,int b) { cout<<"B::int lambda(int a,int b)"<<endl; return a+b; } }; typedef void( *Fun )( void ); int main(int argc, char* argv[]) { B b; Fun pFun; cout<<sizeof(b)<<endl; //如何找到一个类的虚函数列表,注意这里很好奇gcc为何会每个虚函数地址后面跟着一个0地址作为结尾符 cout<<"--------------find virtual tables test:-------------"<<endl; for(int i = 0 ; i < 5; i=i+2) { pFun = (Fun)*((int*)*(int*)(&b)+i); pFun(); } //多态测试 cout<<"----------------A multi situation test:---------------"<<endl; A *base = new B(); base->lambda(2,3); long long x=9,y=10; base->lambda(x,y); base->g(); base->f(); //子类虚函数重载测试 B *b_base = new B(); cout<<"-----------------------B's f virtual func:--------------"<<endl; b_base->lambda(); b_base->lambda(2,3); b_base->f(); b_base->g(); b_base->g(3,3); //父类函数测试 cout<<"-------------------------A's func test:------------------"<<endl; A *a_base = new A(); a_base->f(); a_base->lambda(6,7); return 0; }
输出结果:
48
————–find virtual tables test:————-
B::void g()
B::void f()
B::virtual g(int a,int b)
—————-A multi situation test:—————
A::void lambda(int a,int b) called:5
A::int lambda(long long a,long long b) called:
B::void g()
B::void f()
———————–B’s f virtual func:————–
B::void lambda()
B::int lambda(int a,int b)
B::void f()
B::void g()
B::virtual g(int a,int b)
————————-A’s func test:——————
A::virtual void f() called
A::void lambda(int a,int b) called:13
数据成员地址为:
(gdb) p &b
8 = (B *) 0x7fffffffe530
(gdb) p &b.oo9 = (int *) 0x7fffffffe538
(gdb) p &b.p
10 = 0x7fffffffe53c “”
(gdb) p &b.pp11 = (int *) 0x7fffffffe540
(gdb) p &b.a
12 = (long long *) 0x7fffffffe548
(gdb) p &b.d13 = 0x7fffffffe550 “”
(gdb) p &b.q
$14 = (long long *) 0x7fffffffe558
相关文章推荐
- C++ 重载,重定义(覆盖),重写名字隐藏
- C++中重定义、重写、重载的区别以及隐藏与覆盖的访问
- C++三大概念要分清--重载,隐藏(重定义),覆盖(重写)
- C++中重定义、重写、重载的区别以及隐藏与覆盖的访问
- 多态(2)纯虚函数与重载、重写(覆盖)、重定义(隐藏)
- C++中的覆盖(重写)、重载、隐藏(重定义)、多态!
- C++覆盖、重载、多态区别 ; 重载、重写(覆盖)、重定义(隐藏)三者区别
- 区分重载,重写(覆盖),重定义(隐藏)
- C++中重定义、重写、重载的区别以及隐藏与覆盖的访问
- c++三大概念要分清--重载,隐藏(重定义),覆盖(重写)
- 【转载】重载 重写(覆盖) 重定义(隐藏)
- 多态(2)纯虚函数与重载、重写(覆盖)、重定义(隐藏)
- 重载、覆盖(重写)、隐藏(重定义)
- 类成员函数中重载/重写(覆盖)/重定义(隐藏)的区别
- C++中重定义、重写、重载的区别以及隐藏与覆盖的访问
- C++中重定义、重写、重载的区别以及隐藏与覆盖的访问
- C++ 重载 覆盖 隐藏 重写 重定义
- c++重载,重写/覆盖,重定义/隐藏
- 类成员函数的重载、覆盖和隐藏(重写)的区别
- C++中重载、重写(覆盖)和隐藏的区别实例分析