您的位置:首页 > 其它

继承与多态

2015-09-20 17:15 253 查看
继承:

保护已有类的特性而构造新类的过程称为继承

在已有类的基础上新增自己的特性而产生新类的过程称为派生

被继承的已有类称为基类(或父类);

派生出的新类称为派生类(或子类);

继承的目的:实现代码重用

派生的目的:当新的问题出现,原有程序无法解决时,需要对原有程序进行改造

三种继承方式:

公有继承,

私有继承,

保护继承。

1:当基类有默认构造函数时,当创建派生类的对象时,派生类的构造函数会自动调用基类的构造函数

2:当激烈没有默认构造函数时,派生类的构造函数必须使用初始化参数列表来调用基类的构造函数

3:在构造子类对象时,先执行父类构造对象,然后执行参数类的构造函数,最后执行子类构造函数。

例:

#include<iostream>
using namespace std;
class Father
{
protected:
int f_data;
public:
Father(int x):f_data(x){}
Father(){f_data=1;}

};
class Son:public Father         <span style="color:#ff6666;"> </span><span style="color:#ff0000;"> //以public继承</span>
{
private:
int s_data;
public:
Son(int x):s_data(x){}
Son(){s_data=11;}
void show()
{
cout<<"f_data:"<<f_data<<endl;  <span style="color:#ff0000;">//打印继承父类的id</span>
cout<<"s_data:"<<s_data<<endl;
}
};

int main()
{
Son s1;
s1.show();
return 0;
}


赋值兼容规则:

派生类对象可以赋值给基类对象 (比如要动物我们可以给猴子)

派生类对象可以初始化基类引用

派生类对象的地址可以赋值给指向基类的指针(放动物的地方我们可以放猴子)

#include<iostream>
using namespace std;
class A
{
public:
void show()
{
cout<<"A"<<endl;
}
};
class B:public A
{
public:
void show()
{
cout<<"B"<<endl;
}
};
class C:public B
{
public:
void show()
{
cout<<"C"<<endl;
}
};
void fun(A* ptr)
{
ptr->show();
}

int main()
{
A a1,*p;      <span style="color:#ff0000;">//通过指针指向,指针首先指向其继承部分,所以一直打印:A</span>
B b1;
C c1;
p=&a1;
fun(p);	   <span style="color:#ff0000;"> //显示为:A</span>
p=&b1;
fun(p);	    <span style="color:#ff0000;">//显示为:A</span>
p=&c1;
fun(p);	   <span style="color:#ff0000;"> //显示为:A</span>
return 0;

}


多态:

c++多态是通过虚函数实现的,虚函数允许子类重新定义成员函数,而子类重写定义弗雷接口的做法成为覆盖或重写

子类需要公有继承父类

定义父类的指针或引用,然后通过指针或引用去调用相应的虚函数

虚函数:

成员函数之前加上virtual 关键字,就是虚成员函数。

判断是否为虚函数:

1:该函数与基类的虚函数有相同的函数名

2:该函数与基类的虚函数有相同的残苏个数与对应的参数类型

3:该函数与基类虚函数有相同的返回值或者满足赋值兼容规则的指针,引用的返回值

#include<iostream>
using namespace std;
class A
{
public:
virtual void show()          <span style="color:#ff0000;">//虚成员函数</span>
{
cout<<"A"<<endl;
}
};
class B:public A
{
public:
void show()		<span style="color:#ff0000;">//虚成员函数</span>
{
cout<<"B"<<endl;
}
};
class C:public B		//虚成员函数
{
public:
void show()
{
cout<<"C"<<endl;
}
};
void fun(A* ptr)
{
ptr->show();
}

int main()
{
A a1,*p;      <span style="color:#ff0000;">//通过虚函数,重写父函数</span>
B b1;
C c1;
p=&a1;
fun(p);	   <span style="color:#ff0000;"> //显示为:A</span>
p=&b1;
fun(p);	    <span style="color:#ff0000;">//显示为:B</span>
p=&c1;
fun(p);	   <span style="color:#ff0000;"> //显示为:C</span>
return 0;

}


多态与非多态区别:

区别就是地址是早绑定还是晚绑定,如果函数的调用在编译期间就可以确定函数的调用地址,并产生代码,就是静态的也就是早绑定是非多态的。而如果函数的调用地址不能在编译期间确定,需要在运行时才确定,这就是晚绑定也称动态联编,是多态的

重载与重写区别:

重载overload:函数名相同,参数列表不同,在同类内部存在,不以返回值判断

重写overwrrte:也称为覆盖,子类重新定义父类中的同名函数。函数特征相同,单数具体实现不同,基类的函数要有关键字virtual,主要是在继承关系中出现。

组合和继承:

组合是has,继承是is,比如眼睛,猴子适合于组合,而动物,猴子适合用继承。

虚拟继承:

沙发:可以看电视,有重量

床:可以睡觉,有重量

沙发床:继承沙发和床,既可以睡觉,又可以看电视
sleeper_sofa:public bed,public sofa
//出错,沙发床不能有两个重量

所以先把重量定义为一类,然后沙发和床都虚拟继承该类。

#include<iostream>
using namespace std;
class Furniture
{
int weight;
public:
Furniture(){cout<<"Furniture()"<<endl;}
~Furniture(){cout<<"~Furniture()"<<endl;}
void setweight(int x)
{
weight=x;
}
void getweight()
{
cout<<weight<<endl;
}
};
class Sofa:<span style="background-color: rgb(255, 204, 0);">virtual</span> public Furniture
{
public:
Sofa(){cout<<"Sofa()"<<endl;}
~Sofa(){cout<<"~Sofa()"<<endl;}
void watch_tv()
{
cout<<"watch_tv"<<endl;
}
};
class Bed:<span style="background-color: rgb(255, 255, 0);">virtual</span> public Furniture
{
public:
Bed(){cout<<"Bed()"<<endl;}
~Bed(){cout<<"~Bed()"<<endl;}
void sleep()
{
cout<<"sleeping"<<endl;
}
};
class Sleepersofa:public Bed,public Sofa
{
public:
Sleepersofa(){cout<<"Sleepersofa()"<<endl;}
~Sleepersofa(){cout<<"~Sleepersofa()"<<endl;}
void Foldout()
{
cout<<"Fold out the sofa"<<endl;
}
};

int main()
{
Sleepersofa s1;
s1.setweight(20);
s1.getweight();
cout<<endl;

}
skywalker@skywalker:~/item$ ./a.out <span style="white-space:pre">	<span style="color:#cc0000;">	</span></span><span style="color:#cc0000;">//结果如下</span>
Furniture()
Bed()
Sofa()
Sleepersofa()
20

~Sleepersofa()
~Sofa()
~Bed()
~Furniture()


构造对象的规则需要扩展以控制多重继承。构造函数按下列顺序被调用:

1:任何虚拟基类的构造函数按照它们被继承的顺序构造

2:任何非虚拟基类的构造函数按照它们被继承的顺序构造;

3:任何成员对象的构造函数按照它们声明的顺序调用;

4:类自己的构造函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: