为了搞清上面几个的关系,做了一些实验
为了搞清上面几个的关系,做了一些实验1.
#include
using namespace std;
class A
{
public:
int f(int a);
};
class B:public A
{
public:
int f(int a, int b);
};
int main()
{
cout<<"test"<}
result:
pass
2.
#include
using namespace std;
class A
{
public:
int f(int a);
};
class B:public A
{
public:
float f(int a);
};
int main()
{
cout<<"test"<}
result:
pass
3.
#include
using namespace std;
class A
{
public:
int f(int a);
};
class B:public A
{
public:
int f(int a);
float f(int a);
};
int main()
{
cout<<"test"<}
result:
test_class.cpp:15: error: ‘float B::f(int)’ cannot be overloaded
test_class.cpp:14: error: with ‘int B::f(int)’
4.
#include
using namespace std;
class A
{
public:
int f(int a);
};
class B:public A
{
public:
int f(int a);
};
int main()
{
cout<<"test"<}
result:
pass
5.
#include
using namespace std;
class A
{
public:
int f(){cout<<"f in class A"<};
class B:public A
{
public:
int f(){cout<<"f in class B"<};
int main()
{
A a;
B b;
A *p1 = &b;
B *p2 = &a;
A &r1 = b;
B &r2 = a;
cout<<"p1->f():"< p1->f();
cout<<"p2->f():"< p2->f();
cout<<"r1.f():"< r1.f();
cout<<"r2.f():"< r2.f();
}
result:
test_class.cpp:24: error: invalid conversion from ‘A*’ to ‘B*’
test_class.cpp:27: error: invalid initialization of reference of type ‘B&’ from expression of type ‘A’
6.
#include
using namespace std;
class A
{
public:
int f(){cout<<"f in class A"<};
class B:public A
{
public:
int f(){cout<<"f in class B"<};
int main()
{
A a;
B b;
A *p1 = &b;
A &r1 = b;
cout<<"p1->f():"< p1->f();
cout<<"r1.f():"< r1.f();
}
result:
p1->f():
f in class A
r1.f():
f in class A
7.
#include
using namespace std;
class A
{
public:
virtual int f(){cout<<"f in class A"<};
class B:public A
{
public:
int f(){cout<<"f in class B"<};
int main()
{
A a;
B b;
A *p1 = &b;
A &r1 = b;
cout<<"p1->f():"< p1->f();
cout<<"r1.f():"< r1.f();
}
result:
p1->f():
f in class B
r1.f():
f in class B
8.
#include
using namespace std;
class A
{
public:
virtual int f(){cout<<"f in class A"<};
class B:public A
{
public:
float f(){cout<<"f in class B"<};
int main()
{
A a;
B b;
A *p1 = &b;
A &r1 = b;
cout<<"p1->f():"< p1->f();
cout<<"r1.f():"< r1.f();
}
result:
test_class.cpp:14: error: conflicting return type specified for ‘virtual float B::f()’
test_class.cpp:8: error: overriding ‘virtual int A::f()’
9.
#include
using namespace std;
class A
{
public:
int f(){cout<<"f in class A"<};
class B:public A
{
public:
float f(){cout<<"f in class B"<};
int main()
{
A a;
B b;
A *p1 = &b;
A &r1 = b;
cout<<"p1->f():"< p1->f();
cout<<"r1.f():"< r1.f();
}
result:
p1->f():
f in class A
r1.f():
f in class A
10.
#include
using namespace std;
class A
{
public:
virtual int f(){cout<<"f in class A"<};
class B:public A
{
public:
int f(int a){cout<<"f in class B"<};
int main()
{
A a;
B b;
A *p1 = &b;
A &r1 = b;
cout<<"p1->f():"< p1->f();
cout<<"r1.f():"< r1.f();
}
result:
p1->f():
f in class A
r1.f():
f in class A
11.
#include
using namespace std;
class A
{
public:
virtual int f(){cout<<"f in class A"<};
class B:public A
{
public:
int f(int a){cout<<"f in class B"<};
int main()
{
A a;
B b;
A *p1 = &b;
A &r1 = b;
cout<<"p1->f():"< p1->f(0);
cout<<"r1.f():"< r1.f(0);
}
result:
test_class.cpp: In function ‘int main()’:
test_class.cpp:28: error: no matching function for call to ‘A::f(int)’
test_class.cpp:8: note: candidates are: virtual int A::f()
test_class.cpp:31: error: no matching function for call to ‘A::f(int)’
test_class.cpp:8: note: candidates are: virtual int A::f()
12.
#include
using namespace std;
class A
{
public:
virtual int f(int a){cout<<"f in class A"<};
class B:public A
{
public:
int f(){cout<<"f() in class B"< int f(int a){cout<<"f(int) in class B"<};
int main()
{
A a;
B b;
A *p1 = &b;
A &r1 = b;
cout<<"p1->f():"< p1->f(0);
cout<<"r1.f():"< r1.f(0);
}
result:
p1->f():
f(int) in class B
r1.f():
f(int) in class B
13.
#include
using namespace std;
class A
{
public:
virtual int f(int a){cout<<"f in class A"<};
class B:public A
{
public:
float f(){cout<<"f() in class B"< int f(int a){cout<<"f(int) in class B"<};
int main()
{
A a;
B b;
A *p1 = &b;
A &r1 = b;
cout<<"p1->f():"< p1->f(0);
cout<<"r1.f():"< r1.f(0);
}
result:
p1->f():
f(int) in class B
r1.f():
f(int) in class B
14.
#include
using namespace std;
class A
{
public:
int f(int a){cout<<"f in class A"<};
class B:public A
{
public:
float f(int a, int b){cout<<"f() in class B"< int f(int a){cout<<"f(int) in class B"<};
int main()
{
A a;
B b;
A *p1 = &b;
A &r1 = b;
cout<<"p1->f():"< p1->f(0);
cout<<"r1.f():"< r1.f(0);
}
result:
p1->f():
f in class A
r1.f():
f in class A
15.
#include
using namespace std;
class A
{
public:
int f(int a,int b, int c){cout<<"f in class A"<};
class B:public A
{
public:
int f(int a, int b = 0){cout<<"f() in class B"<};
int main()
{
A a;
B b;
A * p1 = &b;
B * p2 = &b;
p2->f(1,2,3);
}
result:
test_class.cpp: In function ‘int main()’:
test_class.cpp:28: error: no matching function for call to ‘B::f(int, int, int)’
test_class.cpp:15: note: candidates are: int B::f(int, int)16.
#include
using namespace std;
class A
{
public:
virtual int f(int a){cout<<"f in class A"<};
class B:public A
{
public:
//using A::f;
int f(int a, int b = 0){cout<<"f() in class B"< int f(int a){cout<<"f(int) in class B"<};
int main()
{
A a;
B b;
A * p1 = &b;
B * p2 = &b;
b.f(1);
}
result:
test_class.cpp: In function ‘int main()’:
test_class.cpp:29: error: call of overloaded ‘f(int)’ is ambiguous
test_class.cpp:15: note: candidates are: int B::f(int, int)
test_class.cpp:16: note: virtual int B::f(int)
17.
#include
using namespace std;
class A
{
public:
virtual int f(int a){cout<<"f in class A"<};
class B:public A
{
public:
float f(int a){cout<<"f(int) in class B"<};
int main()
{
//
}
result:
test_class.cpp:14: error: conflicting return type specified for ‘virtual float B::f(int)’
test_class.cpp:8: error: overriding ‘virtual int A::f(int)’
18.
#include
using namespace std;
class A
{
public:
virtual int f(int a){cout<<"f in class A"<};
class B:public A
{
public:
float f(int a,int b){cout<<"f(int) in class B"<};
int main()
{
//
}
result:
pass
通过上面的实验,总结出下面的几点:
1)父子之间非虚函数规则:函数由三部分组成,函数名,参数列表,返回值,覆盖可以说是只由函数名决定的,也就是说,只要子函数中有个名字叫做f的函数,那么父函数中所有叫这个名字的函数都会被覆盖掉,除非显示的调用(即使用A::f),所以说父子类之间的同名函数,只要不是虚函数,是不会引起编译错误的。
2)同一类中函数规则:具体到某个类,其同名函数是要符合重载的规则,具体就是函数名相同,参数列表必须不同,返回值可同可不同。在此同时,还必须注意参数默认值所可能引起的歧义,参照16
3)父子之间虚函数规则:虚函数的规则必须是有virtual关键字,并且函数的三部分都保持一致,可以参照17。需要注意的是18这种情况,我的理解是:在有virtual关键字的情况下,编译器通过函数名和参数列表来判断父子之间是不是要满足virtual函数规则,如果要满足这种规则,那么,两个函数的返回值也是要一样的。另外虚函数的作用就是:有一个基类A,而类B,类C分别继承了A类,那么我可以使用A的指针A *p,通过分别赋不同的A B C类型的对象值,来统一通过p来调用不同的虚函数。虚函数必须通过指针或者引用来实现这一功能。
4)父子类的指针和引用在不使用虚函数的情况下,对于同名函数,子类指针是不认父类函数的,而对于不同名的函数,子类指针在自己的类中找不到某个函数时会去访问父类中的public函数。指针和引用所起的效果是基本上相同的,我们经常的将一个父类的指针指向子类的对象,反过来是错误的。
再总结一下,对于不同名的函数,可以说,在public权限下,父类的函数对于子类是完全可见的,也就是说子类找不到名字的函数,他会去父类中去找。对于同名的虚函数(virtual关键字+(函数名,参数列表相同-->决定了返回值也必须相同)),按照虚函数规则动态访问对于同名的非虚函数,按照覆盖规则进行,即父类的同名函数对子类不可见,除非显示的用父类的名字引导,(即用A::之类)用一个父类类型的指针指向一个子类对象和用一个父类类型的引用指向一个子类对象多达到的效果是一样的。