【继承】

继承的访问控制域 图

类型兼容性原则  指针 与 引用

用子类直接初始化父类

类的继承模型示意 图

【继承结论】

【非常重要的概念】

继承与组合混搭情况下,构造和析构调用原则 

原则:先构造父类,再构造成员变量、最后构造自己

先析构自己,在析构成员变量、最后析构父类

继承中,同名的成员变量的处理办法

继承中,同名的成员函数的处理办法

派生类中的static关键字

如果静态成员变量,你没有使用,也没有初始化的话 编译不会报错

经典错误 :

类中函数默认是private的,无法在外部访问 具体表现为: 我连变量都无法创建

传说中的多继承,让我们来看看大家都嫌弃的C++多继承

多继承的二义性

虚继承

虚继承的局限性

多继承, 手动调用域作用

虚继承: virtual关键字 

【多态】

【问题引出】【指针 引用 】类型兼容性原则上的函数重写,为什么效果?

【问题的解决】多态的使用

一般情况下,为了醒目,都加上virtual关键字

【多态案例】雷霆战机

如果没写virtual关键字,C++编译时根据A类型去执行power函数,在编译阶段就决定了函数的调用

写了virtuial关键字,迟绑定,在运行的时候,很据具体的对象类型,执行不同的函数,表现成多态

【面试题】【虚析构函数是用来干嘛的?】

【答案】通过父类指针,把所有的子类对象的析构函数执行一遍,释放所有子类资源

不加virtual 不使用函数,可以正常析构所有子类的资源

【面试题】【很难】函数重载·重写·重定义

继承重要说明 

1、子类拥有父类的所有成员变量和成员函数   

4、子类可以拥有父类没有的方法和属性 

 

2、子类就是一种特殊的父类 

3、子类对象可以当作父类对象使用 

3.2派生类的访问控制 

派生类继承了基类的全部成员变量和成员方法(除了构造和析构之外的成员方法),但是这些成员的访问属性,在派生过程中是可以调整的。 

类的继承,初步:

chunli@Linux:~$ cat main.cpp #include 
using namespace std;class Parent{public: void printf() { cout << "I'm Parent \n"; } int a;};//继承的三种方式//:public Parent//:protected Parent//:private Parentclass A :public Parent{};int main(){ A a1; a1.printf(); a1.a = 6; cout <<  a1.a << endl; return 0;}chunli@Linux:~$ g++ -g  -o run main.cpp && ./run I'm Parent 6chunli@Linux:~$

2 继承的访问控制域

C++中子类对外访问属性表

父类成员访问级别

public

proteced

private

public

public

proteced

private

proteced

proteced

proteced

private

private

private

private

Private

【难点】类型兼容性原则 

类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。类型兼容规则中所指的替代包括以下情况:

子类对象可以当作父类对象使用

子类对象可以直接赋值给父类对象

子类对象可以直接初始化父类对象

父类指针可以直接指向子类对象

父类引用可以直接引用子类对象

在替代之后,派生类对象就可以作为基类的对象使用,但是只能使用从基类继承的成员。

类型兼容规则是多态性的重要基础之一。

总结:子类就是特殊的父类 (base *p = &child;)

类型兼容性原则:程序热身:

chunli@Linux:~$ cat main.cpp #include 
using namespace std;class Parent{public: void printf_p() { cout << "I'm Parent \n"; } int a;};class A :public Parent{public: void printf_c() { cout << "I'm child \n"; }};int main(){ A a1; a1.printf_p(); a1.printf_c(); return 0;}chunli@Linux:~$ g++ -g  -o run main.cpp && ./run I'm Parent I'm child chunli@Linux:~$

【重点】类型兼容性原则:定义父类指针,指向子类对象,子类调用父类函数 

【注意】尽管这个是父类指针,指向了儿子,但是还是无法调用儿子的函数

chunli@Linux:~$ cat main.cpp #include 
using namespace std;class Parent{public: void printf_p() { cout << "I'm Parent \n"; } int a;};class Child :public Parent{public: void printf_c() { cout << "I'm child \n"; }};int main(){ Child c1; Parent *p1 = NULL; p1 = &c1; p1->printf_p(); return 0;}chunli@Linux:~$ g++  -o run main.cpp  && ./run I'm Parent chunli@Linux:~$

对象的指针 与 引用

赋值兼容性原则:把子类对象传给父类,C++编译器不会报错

chunli@Linux:~$ cat main.cpp #include 
using namespace std;class Parent{public: void printf_p() { cout << "I'm Parent \n"; } int a;};class Child :public Parent{public: void printf_c() { cout << "I'm child \n"; }};void fun_1(Parent *p){ p->printf_p();}void fun_2(Parent &p){ p.printf_p();}int main(){ Child c1; Parent p1; fun_1(&c1); fun_1(&p1); fun_2(c1); fun_2(p1); return 0;}chunli@Linux:~$ g++  -o run main.cpp  && ./run I'm Parent I'm Parent I'm Parent I'm Parent chunli@Linux:~$

用子类直接初始化父类:

chunli@Linux:~$ cat main.cpp #include 
using namespace std;class Parent{public: void printf_p() { cout << "I'm Parent \n"; } int a;};class Child :public Parent{public: void printf_c() { cout << "I'm child \n"; }};int main(){ Child c1; Parent p1  = c1;//因为子类就是特殊的父类,会调用拷贝构造函数 Parent p2(c1); return 0;}chunli@Linux:~$ g++  -o run main.cpp  && ./run chunli@Linux:~$

类的继承模型示意图

继承中的对象模型 

类在C++编译器的内部可以理解为结构体

子类是由父类成员叠加子类新成员得到的

继承中构造和析构 

问题:如何初始化父类成员?父类与子类的构造函数有什么关系

在子类对象构造时,需要调用父类构造函数对其继承得来的成员进行初始化

在子类对象析构时,需要调用父类析构函数对其继承得来的成员进行清理

【结论】

先调用父类的构造函数,再调用子类的构造函数

先调用子类的析构函数,再调用父类的析构函数

chunli@Linux:~$ cat main.cpp #include 
using namespace std;class Parent{public: Parent(int a,int b) { this->a = a; this->b = b; cout << "Parent 构造函数 \n"; } ~Parent() { cout << "Parent 析构函数 \n"; }private: int a; int b;};class Child :public Parent{public: Child(int a,int b,int c):Parent(b,c) { this->c = c; cout << "Child 构造函数\n"; } ~Child() { cout << "Child 析构函数\n"; } void printf_c() { cout << "I'm child \n"; }private: int c;};int main(){ Child c1(1,2,3); return 0;}chunli@Linux:~$ g++  -o run main.cpp  && ./run Parent 构造函数 Child 构造函数Child 析构函数Parent 析构函数 chunli@Linux:~$

【非常重要的概念】

继承与组合混搭情况下,构造和析构调用原则 

原则:先构造父类,再构造成员变量、最后构造自己

        先析构自己,在析构成员变量、最后析构父类

chunli@Linux:~$ cat main.cpp #include 
using namespace std;class Obj{public: Obj(int a) { cout << "Obj 构造函数 a="<
<

继承中,同名的成员变量的处理办法:

chunli@Linux:~$ cat main.cpp #include 
using namespace std;class A{public: void get_1() { cout <
<< endl; } int a; int b;};class B :public A{public: void get_2() { cout <
<< endl; } int b; int c;};int main(){ B b1; b1.b = 1111; b1.A::b  = 2222; b1.get_2(); b1.get_1(); //当然也可以这么干: b1.B::b = 100; b1.A::b = 200; b1.get_2(); b1.get_1(); return 0;}chunli@Linux:~$ g++  -o run main.cpp  && ./run 11112222100200chunli@Linux:~$

继承中,同名的成员函数的处理办法:

chunli@Linux:~$ cat main.cpp #include 
using namespace std;class A{public: void get_1() { cout <
<< endl; } void fun() { cout << "AAAAAAAAAAAAAAAAAAAAAA "<< endl; } int a; int b;};class B :public A{public: void get_2() { cout <
<< endl; } void fun() { cout << " BBBBBBBBBBBBBBBBBB "<< endl; } int b; int c;};int main(){ B b1; b1.b = 1111; b1.A::b  = 2222; b1.fun(); //默认是调用自己的函数 //当然也可以这么干: b1.A::fun(); b1.B::fun(); return 0;}chunli@Linux:~$ g++  -o run main.cpp  && ./run  BBBBBBBBBBBBBBBBBB AAAAAAAAAAAAAAAAAAAAAA  BBBBBBBBBBBBBBBBBB chunli@Linux:~$

派生类中的static关键字

继承和static关键字在一起会产生什么现象哪?

理论知识

基类定义的静态成员,将被所有派生类共享

根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具有不同的访问性质 (遵守派生类的访问控制)

派生类中访问静态成员,用以下形式显式说明:

类名 :: 成员

    或通过对象访问对象名 . 成员

chunli@Linux:~$ cat main.cpp #include 
using namespace std;class A{public: static int a;};//完成初始化int A::a = 99;class B :private A{public: void fun() { cout << a << endl; }};int main(){ B b1; b1.fun(); //b1.a = 100; /* 不能在类的外面访问private的成员变量 main.cpp: In function ‘int main()’: main.cpp:10:5: error: ‘int A::a’ is inaccessible int A::a = 99; */ return 0;}chunli@Linux:~$ g++  -o run main.cpp  && ./run 99chunli@Linux:~$

【注意隐患】

如果静态成员变量,你没有使用,也没有初始化的话

编译不会报错:

chunli@Linux:~$ chunli@Linux:~$ cat main.cpp #include 
using namespace std;class A{public: static int a;};//完成初始化//int A::a = 99; 这句话不简单是变量的赋值,更重要的是你要给我分配内容class B :private A{public: void fun() {// cout << a << endl; }};int main(){ B b1; b1.fun(); return 0;}chunli@Linux:~$ g++  -o run main.cpp  && ./run chunli@Linux:~$

【经典错误:】

类中函数默认是private的,无法在外部访问

具体表现为:

我连变量都无法创建

chunli@Linux:~$ cat main.cpp #include 
using namespace std;class A{ A() { cout << "A \n"; }};int main(){ A a1; return 0;}chunli@Linux:~$ g++  -o run main.cpp  && ./run main.cpp: In function ‘int main()’:main.cpp:6:2: error: ‘A::A()’ is private  A()  ^

传说中的多继承,让我们来看看大家都嫌弃的C++多继承

1.正常的多继承语法

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: A(int a) { this->a = a; } void fun_1() { cout << "AAAAAAAAAAAAAAAA\n"; } int a;};class B{public: B(int a) { this->a = a; } void fun_2() { cout << "BBBBBBBBBBBBBBBBBBBBB\n"; } int a;};class C :public A,public B{public: C(int a,int b,int c):A(a),B(b) { this->a = c; } void fun_3() { cout << "CCCCCCCCCCCCCCCCCCC\n"; } int a;};int main(){ C c1(1,2,3); c1.fun_1(); c1.fun_2(); c1.fun_3(); return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCchunli@http://990487026.blog.51cto.com~$

多继承的二义性

C++编译器不知道谁那个成员属性

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: int a;};class B{public: int a;};class C :public A,public B{};int main(){ C c1; c1.a = 100; return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run main.cpp: In function ‘int main()’:main.cpp:23:5: error: request for member ‘a’ is ambiguous  c1.a = 100;     ^

制作C++编译器的大牛们想的办法:虚继承

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: int a;};class B :virtual public A{};class C :virtual public A{};class D:public B,public C{ };int main(){ D d1; d1.a = 100; cout << "a="<
<

虚继承的局限性:

因为虚继承只能解决共同一个老祖先的问题

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: int a;};class B {public: int a;};class C :virtual public A,virtual public B{};class D : public A, public B{};int main(){ C c1; c1.a = 100; cout << "a="<
<

多继承就是这样,只有程序员自己解决:

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: int a;};class B {public: int a;};class C : public A, public B{};int main(){ C c1; c1.A::a = 100; c1.B::a = 200; cout << "A::a="<
<< endl; cout << "B::a="<
<< endl; return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run A::a=100B::a=200chunli@http://990487026.blog.51cto.com~$

加不加virtual关键字的区别:

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: int a;};class B:public A {};class C : public A{};int main(){ cout << sizeof(A) << endl; cout << sizeof(B) << endl; cout << sizeof(C) << endl; return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run 444chunli@http://990487026.blog.51cto.com~$

加了virtual之后,C++编译器会偷偷地添加属性,实现虚继承

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: int a;};class B:virtual public A {};class C:virtual public A{};int main(){ cout << sizeof(A) << endl; cout << sizeof(B) << endl; cout << sizeof(C) << endl; return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run 41616chunli@http://990487026.blog.51cto.com~$

【多态】

【难点】面向对象:封装-> 继承-> 多态

封装:突破了函数的概念,用类做函数的参数,使用对象的属性和方法

继承:前人的成果,可以直接拿来用,代码复用性

多态:后人的成果,可以直接拿来用,可以使用未来【软件行业的最高境界】

C语言中,指针的间接赋值是指针存在的最大意义

1定义两个变量  2建立关联  3间接修改变量的值

面向对象:多态成立的3个条件

1 要有继承,  2 函数重写   3 用父类指针指向子类

【问题引出】【指针】类型兼容性原则上的函数重写:

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: A(int a) { this->a = a; //cout << "AAAAAAAAAAA\n"; } void fun() { cout << "AAAAAAAAAAA\n"; } int a;};class B:public A {public: B(int a):A(a) { this->a = a; //cout << "BBBBBBBBBBBB\n"; } void fun() { cout << "BBBBBBBBBBBB\n"; } int a;};int main(){ A *p = NULL; A a(10); B b(20); p = &a; p->fun(); p = &b; //因为赋值兼容性原则,C++编译器不报错 p->fun(); //这儿执行的是父类的函数 return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run AAAAAAAAAAAAAAAAAAAAAAchunli@http://990487026.blog.51cto.com~$

【问题引出】【引用】类型兼容性原则上的函数重写:

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: A(int a) { this->a = a; //cout << "AAAAAAAAAAA\n"; } void fun() { cout << "AAAAAAAAAAA\n"; } int a;};class B:public A {public: B(int a):A(a) { this->a = a; //cout << "BBBBBBBBBBBB\n"; } void fun() { cout << "BBBBBBBBBBBB\n"; } int a;};int main(){ A a(10); B b(20); A &p = a; p.fun(); p = b; p.fun(); return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run AAAAAAAAAAAAAAAAAAAAAAchunli@http://990487026.blog.51cto.com~$

【问题引出】函数的方式【指针】【引用】效果还是这样

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: A(int a) { this->a = a; } void fun() { cout << "AAAAAAAAAAA\n"; } int a;};class B:public A {public: B(int a):A(a) { this->a = a; } void fun() { cout << "BBBBBBBBBBBB\n"; } int a;};void fun1(A *p){ p->fun();}void fun2(A &p){ p.fun();}int main(){ A a(10); B b(20); fun1(&a); fun1(&b); fun2(a); fun2(b); return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAchunli@http://990487026.blog.51cto.com~$

【问题的解决  多态的使用】

一般情况下,为了醒目,都加上virtual关键字

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: A(int a) { this->a = a; } virtual void fun() { cout << "AAAAAAAAAAA\n"; } int a;};class B:public A {public: B(int a):A(a) { this->a = a; } virtual void fun() //一般情况下,只要父类中写了virtual,之类中可写可不写 { cout << "BBBBBBBBBBBB\n"; } int a;};void fun1(A *p){ p->fun();}void fun2(A &p){ p.fun();}int main(){ A a(10); B b(20); fun1(&a); fun1(&b); fun2(a); fun2(b); return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run AAAAAAAAAAABBBBBBBBBBBBAAAAAAAAAAABBBBBBBBBBBBchunli@http://990487026.blog.51cto.com~$

【多态案例】

模拟两个战机PK

A为我方老战机

B为我方高级战机

C为敌机

这样在框架下干活

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
using namespace std;class A{public: virtual int power() { return 10; }};class B:public A {public: virtual int power() //一般情况下,只要父类中写了virtual,之类中可写可不写 { return 25; }};class C{public: int power() { return 15; }};void play(A *p1,C *p2){ if(p1->power() > p2->power()) { cout << "win \n"; } else { cout << "fail \n"; }}int main(){ A a; B b; C c; play(&a,&c); play(&b,&c); return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run fail win chunli@http://990487026.blog.51cto.com~$

【结论】:

如果没写virtual关键字,C++编译时根据A类型去执行power函数,在编译阶段就决定了函数的调用

写了virtuial关键字,迟绑定,在运行的时候,很据具体的对象类型,执行不同的函数,表现成多态

【面试题】【虚析构函数是用来干嘛的?】

【引出问题】

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
#include 
using namespace std;class A{public: A() { p = new char[20]; strcpy(p,"Hello"); cout << " AAAAAAAAAAAA\n"; } ~A() { delete []p; cout << "~AAAAAAAAAAAA\n"; }private: char *p;};class B:public A{public: B() { p = new char[20]; strcpy(p,"Linux"); cout << " BBBBBBBBBBBBBBBB\n"; } ~B() { delete []p; cout << "~BBBBBBBBBBBBBBBB\n"; }private: char *p;};class C:public B{public: C() { p = new char[20]; strcpy(p,"Ubuntu"); cout <<  " CCCCCCCCCCCCCCCCCCCCC\n"; } ~C() { delete []p; cout <<  "~ CCCCCCCCCCCCCCCCCCCCC\n"; }private: char *p;};void fun(A *p)//赋值兼容性原则{ delete p;  // 这种语法不会表现为多态}int main(){ C *p = new C; fun(p); return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run  AAAAAAAAAAAA BBBBBBBBBBBBBBBB CCCCCCCCCCCCCCCCCCCCC~AAAAAAAAAAAAchunli@http://990487026.blog.51cto.com~$

【答案】通过父类指针,把所有的子类对象的析构函数执行一遍,释放所有子类资源

【原理】如果没写virtual关键字,C++编译时根据A类型去执行power函数,在编译阶段就决定了函数的调用

写了virtuial关键字,迟绑定,在运行的时候,很据具体的对象类型,执行不同的函数,表现成多态

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
#include 
using namespace std;class A{public: A() { p = new char[20]; strcpy(p,"Hello"); cout << " AAAAAAAAAAAA\n"; } virtual ~A() { delete []p; cout << "~AAAAAAAAAAAA\n"; }private: char *p;};class B:public A{public: B() { p = new char[20]; strcpy(p,"Linux"); cout << " BBBBBBBBBBBBBBBB\n"; } ~B() { delete []p; cout << "~BBBBBBBBBBBBBBBB\n"; }private: char *p;};class C:public B{public: C() { p = new char[20]; strcpy(p,"Ubuntu"); cout <<  " CCCCCCCCCCCCCCCCCCCCC\n"; } ~C() { delete []p; cout <<  "~CCCCCCCCCCCCCCCCCCCCC\n"; }private: char *p;};void fun(A *p) //父类写有virtual关键字{ delete p;}int main(){ C *p = new C; fun(p); return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run  AAAAAAAAAAAA BBBBBBBBBBBBBBBB CCCCCCCCCCCCCCCCCCCCC~CCCCCCCCCCCCCCCCCCCCC~BBBBBBBBBBBBBBBB~AAAAAAAAAAAAchunli@http://990487026.blog.51cto.com~$

不加virtual 不使用函数,可以正常析构所有子类的资源:

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
#include 
using namespace std;class A{public: A() { p = new char[20]; strcpy(p,"Hello"); cout << " AAAAAAAAAAAA\n"; } ~A() { delete []p; cout << "~AAAAAAAAAAAA\n"; }private: char *p;};class B:public A{public: B() { p = new char[20]; strcpy(p,"Linux"); cout << " BBBBBBBBBBBBBBBB\n"; } ~B() { delete []p; cout << "~BBBBBBBBBBBBBBBB\n"; }private: char *p;};class C:public B{public: C() { p = new char[20]; strcpy(p,"Ubuntu"); cout <<  " CCCCCCCCCCCCCCCCCCCCC\n"; } ~C() { delete []p; cout <<  "~CCCCCCCCCCCCCCCCCCCCC\n"; }private: char *p;};int main(){ C *p = new C; delete p; return 0;}chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run  AAAAAAAAAAAA BBBBBBBBBBBBBBBB CCCCCCCCCCCCCCCCCCCCC~CCCCCCCCCCCCCCCCCCCCC~BBBBBBBBBBBBBBBB~AAAAAAAAAAAAchunli@http://990487026.blog.51cto.com~$

【面试题】【很难】函数重载·重写·重定义

chunli@http://990487026.blog.51cto.com~$ cat main.cpp #include 
#include 
#include 
using namespace std;class Parent{ //这个三个函数都是重载关系public:  void func()  { } void func(int i) { } void func(int i, int j) { } void func(int i, int j, int m , int n) { }};class Child : public Parent{ public:  void func(int i, int j) { } void func(int i, int j, int k) { }};int main(){ Child c1; c1.func(); return 0;}提示在子类中找不到对用的函数chunli@http://990487026.blog.51cto.com~$ g++  -o run main.cpp  && ./run main.cpp: In function ‘int main()’:main.cpp:43:10: error: no matching function for call to ‘Child::func()’  c1.func();          ^

分析:看图

子类无法重载父类的函数,父类同名函数将被名称覆盖

c1.func();

func函数的名字,在子类中发生了名称覆盖;子类的函数的名字,占用了父类的函数的名字的位置

因为子类中已经有了func名字的重载形式。。。。

编译器开始在子类中找func函数。。。。但是没有0个参数的func函数 

c1.func(1, 3, 4, 5);

1 C++编译器 看到func名字 ,因子类中func名字已经存在了(名称覆盖).

所以c++编译器不会去找父类的4个参数的func函数

2 c++编译器只会在子类中,查找func函数,找到了两个func,一个是2个参数的,一个是3个参数的.

3 C++编译器开始报错.....  error C2661: “Child::func”: 没有重载函数接受 4 个参数

4 若想调用父类的func,只能加上父类的域名..这样去调用..