一、扫盲
下面这几个名词我以前是懵逼的,直到最近认认真真的看了下,才明白,哈哈,写在这吧。
1.继承: 子类拥有了父类的public财产(私有成员其实也有,但是访问不了),通过子类调用函数时,编译器先在子类中找相应的函数,找不到的话再去父类找;
1.1派生:一句话概括:子类继承了父类,父类派生了子类。
2.多态:多态是指使用相同的函数名来访问函数不同的实现方法,即“一种接口,多种方法”,用相同的形式访问一组通用的运算,每个运算可能对应的行为不同。C++支持编译时多态和运行时多态,运算符重载和函数重载就是编译时多态,而派生类和虚函数实现运行时多态。运行时多态的基础是基类指针,基类指针可以指向任何派生类对象。另一种说法(其实意思是一样的),子类可以重写父类的某个函数,从而为这个函数提供不同于父类的行为。一个父类的多个子类可以为同一个函数提供不同的实现,从而在父类这个公共的接口下,表现出多种行为,需要特别指出,多态包含1.虚函数多态、2模板多态、3重载、4转换。
2.1.虚函数多态:
2.2.模版多态:
2.3.转换:
2.4.重载:
二、细致讲解,包含很多实例
1.继承与多态
摘自http://blog.youkuaiyun.com/eric_arrow/article/details/9111963(我认为重要的地方我都标注下啊)
1. 子类拥有了父类的public财产(私有成员其实也有,但是访问不了),通过子类调用函数时,编译器先在子类中找相应的函数,找不到的话再去父类找。
如此一来,如果父类和子类定义了一样的函数(包括参数列表),子类的函数会覆盖父类函数。
如果,父类定义了子类的同名函数,但是参数列表不同,子类的也会被覆盖隐藏,如 果想通过子类调用父类的函数,需要显示的说明,比如 b.A::XXXX(p1, p2)
#include <iostream>
using namespace std;
class A
{
public:
A() {}
~A() {}
void print() { cout << "This is A\n"; }
};
class B: public A
{
public:
B() {}
~B() {}
void print() { cout << "This is B\n"; }
};
int main()
{
A a;
B b;
A *pa = &a;
B *pb = &b;
pa->print();
pb->print();
getchar();
return 0;
}
所以这段代码输出 This is A 和 This is B
2. 下面的代码
#include <iostream>
using namespace std;
class A
{
public:
A() {}
~A() {}
void print() { cout << "This is A\n"; }
};
class B: public A
{
public:
B() {}
~B() {}
void print() { cout << "This is B\n"; }
};
int main()
{
A a;
B b;
A *pa = &a;
A *pb = &b; // 这行是关键
pa->print();
pb->print();
getchar();
return 0;
}
居然,输出是 两个 “This is A”。
3. 所以虚函数便应运而生,很好解决了同名函数继承的多态问题。
#include <iostream>
using namespace std;
class A
{
public:
A() {}
~A() {}
virtual void print() { cout << "This is A\n"; }
};
class B: public A
{
public:
B() {}
~B() {}
void print() { cout << "This is B\n"; }
};
int main()
{
A a;
B b;
A *pa = &a;
A *pb = &b;
pa->print();
pb->print();
getchar();
return 0;
}
输出是 This is A 和 This is B
PS。虚函数的多态,严格按照函数名+参数名。也就是说子类和父类的函数名和参数都得完全一致。
而函数隐藏却不需要这么严格,只要函数名一样的就隐藏函数。
2.隐藏
看下边这个例子,B继承A 为什么main函数执行fun(x),fun(x,y)时编译通不过
class A
{
public:
void f(int i,