【继承】
继承的访问控制域 图
类型兼容性原则 指针 与 引用
用子类直接初始化父类
类的继承模型示意 图
【继承结论】
【非常重要的概念】
继承与组合混搭情况下,构造和析构调用原则
原则:先构造父类,再构造成员变量、最后构造自己
先析构自己,在析构成员变量、最后析构父类
继承中,同名的成员变量的处理办法
继承中,同名的成员函数的处理办法
派生类中的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 <
}
int a;
};
//继承的三种方式
//:public Parent
//:protected Parent
//:private Parent
class A :public Parent
{
};
int main()
{
A a1;
a1.printf();
a1.a = 6;
cout <
return 0;
}
chunli@Linux:~$ g++ -g -o run main.cpp && ./run
I'm Parent
6
chunli@Linux:~$
2 继承的访问控制域
C++中子类对外访问属性表父类成员访问级别
继
承
方
式publicprotecedprivate
publicpublicprotecedprivate
protecedprotecedprotecedprivate
privateprivateprivatePrivate
【难点】类型兼容性原则
类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。类型兼容规则中所指的替代包括以下情况:
子类对象可以当作父类对象使用
子类对象可以直接赋值给父类对象
子类对象可以直接初始化父类对象
父类指针可以直接指向子类对象
父类引用可以直接引用子类对象
在替代之后,派生类对象就可以作为基类的对象使用,但是只能使用从基类继承的成员。
类型兼容规则是多态性的重要基础之一。
总结:子类就是特殊的父类 (base *p = &child;)
类型兼容性原则:程序热身:chunli@Linux:~$ cat main.cpp
#include
using namespace std;
class Parent
{
public:
void printf_p()
{
cout <
}
int a;
};
class A :public Parent
{
public:
void printf_c()
{
cout <
}
};
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 <
}
int a;
};
class Child :public Parent
{
public:
void printf_c()
{
cout <
}
};
int main()
{
Childc1;
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 <
}
int a;
};
class Child :public Parent
{
public:
void printf_c()
{
cout <
}
};
void fun_1(Parent *p)
{
p->printf_p();
}
void fun_2(Parent &p)
{
p.printf_p();
}
int main()
{
Childc1;
Parentp1;
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 <
}
int a;
};
class Child :public Parent
{
public:
void printf_c()
{
cout <
}
};
int main()
{
Childc1;
Parentp1 = c1;//因为子类就是特殊的父类,会调用拷贝构造函数
Parentp2(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()
{
cout <
}
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()
{
cout <
}
void printf_c()
{
cout <
}
private:
int c;
};
int main()
{
Childc1(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()
{
cout <
}
};
class Parent:public Obj
{
public:
Parent(int a,int b):Obj(11)
{
cout <
}
~Parent()
{
cout <
}
};
class Child :public Parent
{
public:
Child(int a,int b,int c):Parent(b,c),obj1(22),obj2(33)
{
cout <
}
~Child()
{
cout <
}
private:
Obj obj1;
Obj obj2;
};
int main()
{
Childc1(1,2,3);
return 0;
}
chunli@Linux:~$ g++ -o run main.cpp && ./run
Obj 构造函数 a=11
Parent 构造函数
Obj 构造函数 a=22
Obj 构造函数 a=33
Child 构造函数
Child 析构函数
Obj 析构函数
Obj 析构函数
Parent 析构函数
Obj 析构函数
chunli@Linux:~$
继承中,同名的成员变量的处理办法:chunli@Linux:~$ cat main.cpp
#include
using namespace std;
class A
{
public:
void get_1()
{
cout <
}
int a;
int b;
};
class B :public A
{
public:
void get_2()
{
cout <
}
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
1111
2222
100
200
chunli@Linux:~$
继承中,同名的成员函数的处理办法:chunli@Linux:~$ cat main.cpp
#include
using namespace std;
class A
{
public:
void get_1()
{
cout <
}
void fun()
{
cout <
}
int a;
int b;
};
class B :public A
{
public:
void get_2()
{
cout <
}
void fun()
{
cout <
}
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 <
}
};
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
99
chunli@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 <
}
};
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 <
}
};
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 <
}
int a;
};
class B
{
public:
B(int a)
{
this->a = a;
}
void fun_2()
{
cout <
}
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 <
}
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
AAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCC
chunli@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 <
return 0;
}
chunli@http://990487026.blog.51cto.com~$ g++ -o run main.cpp && ./run
a=100
chunli@http://990487026.blog.51cto.com~$
虚继承的局限性:
因为虚继承只能解决共同一个老祖先的问题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 <
D d1;d1.a = 100;
cout <
return 0;
}
chunli@http://990487026.blog.51cto.com~$ g++ -o run main.cpp && ./run
main.cpp: In function ‘int main()’:
main.cpp:25:11: error: request for member ‘a’ is ambiguous
C c1; c1.a = 100;
^
main.cpp:13:6: note: candidates are: int B::a
int a;
^
main.cpp:7:6: note: int A::a
int a;
^
main.cpp:26:19: error: request for member ‘a’ is ambiguous
cout <
^
main.cpp:13:6: note: candidates are: int B::a
int a;
^
main.cpp:7:6: note: int A::a
int a;
^
main.cpp:28:11: error: request for member ‘a’ is ambiguous
D d1; d1.a = 100;
^
main.cpp:13:6: note: candidates are: int B::a
int a;
^
main.cpp:7:6: note: int A::a
int a;
^
main.cpp:29:19: error: request for member ‘a’ is ambiguous
cout <
^
main.cpp:13:6: note: candidates are: int B::a
int a;
^
main.cpp:7:6: note: int A::a
int a;
^
chunli@http://990487026.blog.51cto.com~$
多继承就是这样,只有程序员自己解决: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 <
cout <
return 0;
}
chunli@http://990487026.blog.51cto.com~$ g++ -o run main.cpp && ./run
A::a=100
B::a=200
chunli@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 <
cout <
cout <
return 0;
}
chunli@http://990487026.blog.51cto.com~$ g++ -o run main.cpp && ./run
4
4
4
chunli@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 <
cout <
cout <
return 0;
}
chunli@http://990487026.blog.51cto.com~$ g++ -o run main.cpp && ./run
4
16
16
chunli@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 <
}
void fun()
{
cout <
}
int a;
};
class B:public A
{
public:
B(int a):A(a)
{
this->a = a;
//cout <
}
void fun()
{
cout <
}
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
AAAAAAAAAAA
AAAAAAAAAAA
chunli@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 <
}
void fun()
{
cout <
}
int a;
};
class B:public A
{
public:
B(int a):A(a)
{
this->a = a;
//cout <
}
void fun()
{
cout <
}
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
AAAAAAAAAAA
AAAAAAAAAAA
chunli@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 <
}
int a;
};
class B:public A
{
public:
B(int a):A(a)
{
this->a = a;
}
void fun()
{
cout <
}
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
AAAAAAAAAAA
AAAAAAAAAAA
AAAAAAAAAAA
AAAAAAAAAAA
chunli@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 <
}
int a;
};
class B:public A
{
public:
B(int a):A(a)
{
this->a = a;
}
virtual void fun() //一般情况下,只要父类中写了virtual,之类中可写可不写
{
cout <
}
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
AAAAAAAAAAA
BBBBBBBBBBBB
AAAAAAAAAAA
BBBBBBBBBBBB
chunli@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 <
}
else
{
cout <
}
}
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 <
}
~A()
{
delete []p;
cout <
}
private:
char *p;
};
class B:public A
{
public:
B()
{
p = new char[20];
strcpy(p,"Linux");
cout <
}
~B()
{
delete []p;
cout <
}
private:
char *p;
};
class C:public B
{
public:
C()
{
p = new char[20];
strcpy(p,"Ubuntu");
cout <
}
~C()
{
delete []p;
cout <
}
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
~AAAAAAAAAAAA
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 <
}
virtual ~A()
{
delete []p;
cout <
}
private:
char *p;
};
class B:public A
{
public:
B()
{
p = new char[20];
strcpy(p,"Linux");
cout <
}
~B()
{
delete []p;
cout <
}
private:
char *p;
};
class C:public B
{
public:
C()
{
p = new char[20];
strcpy(p,"Ubuntu");
cout <
}
~C()
{
delete []p;
cout <
}
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
~AAAAAAAAAAAA
chunli@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 <
}
~A()
{
delete []p;
cout <
}
private:
char *p;
};
class B:public A
{
public:
B()
{
p = new char[20];
strcpy(p,"Linux");
cout <
}
~B()
{
delete []p;
cout <
}
private:
char *p;
};
class C:public B
{
public:
C()
{
p = new char[20];
strcpy(p,"Ubuntu");
cout <
}
~C()
{
delete []p;
cout <
}
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
~AAAAAAAAAAAA
chunli@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,只能加上父类的域名..这样去调用..