虚继承c语言例子,C++基础6 【继承】 类型兼容 satatic 多继承 虚继承 【多态】 案例 虚析构函数 重载重写重定义...

【继承】

继承的访问控制域 图

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

用子类直接初始化父类

类的继承模型示意 图

【继承结论】

【非常重要的概念】

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

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

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

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

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

派生类中的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++编译器的内部可以理解为结构体

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

df6d2fa8aa09313e4fbe5751de6a5c69.png

72686d080652350124d4d19ba8fa4789.png

继承中构造和析构

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

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

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

【结论】

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

先调用子类的析构函数,再调用父类的析构函数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++多继承

fbb7fe4bb0f88927c915efaf32470b7b.png

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++编译器的大牛们想的办法:虚继承

d4a7c6b8b880079af2f7a48315cede2c.pngchunli@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();

^

6ba1f13cea7a989cbb1531a18167b0f0.png

分析:看图

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

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,只能加上父类的域名..这样去调用..

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值