继承机制
继承机制是面向对象编程技术中的基本特征之一。继承实现了代码重用和代码扩充,大大提高了程序开发的效率。
基类和派生类
通过继承机制可以利用已有的数据类型来定义新的数据。根据一个类创建一个新类的过程称为继承,也称派生。新类自动具有原类的成员,根据需要还可以增加新成员。被继承的类称为基类,或者父类,而派生出来的类称为派生类,又称子类。
继承的种类
单继承
基本格式:
class <类名> :<继承方式><基类名>
{
public:
...
protected:
...
private:
}
public: 共有继承方式
protected: 保护继承方式
private: 私有继承方式 (默认方式)
#include <iostream>
using namespace std;
class Point
{
public:
Point(int x = 0, int y = 0);
void setPoint(int x,int y);
void printPoint();
~Point();
private:
int _x;
int _y;
};
Point::Point(int x , int y)
{
_x = x;
_y = y;
cout<<"Point Constructor"<<endl;
}
void Point::setPoint(int x,int y)
{
_x = x;
_y = y;
}
void Point::printPoint()
{
cout<<"("<<_x<<","<<_y<<")"<<endl;
}
Point::~Point()
{
cout<<"Point destructor"<<endl;
}
class Circle :public Point
{
public:
Circle(int x = 0, int y = 0, int r = 0)
{
setPoint(x,y);
_r = r;
cout<<"Circle Constructor"<<endl;
}
void printCircle()
{
printPoint();
cout<<_r<<endl;
}
~Circle()
{
cout<<"Circle destructor"<<endl;
}
private:
int _r;
};
int main()
{
Circle c1(1,2,4);
c1.printCircle();
c1.printPoint();
return 0;
}
派生类的访问限制
公有继承:
#include <iostream>
using namespace std;
class A
{
public:
int _x;
void setX(int x)
{
_x = x;
cout<<"x = "<<_x<<endl;
}
protected:
int _y;
void sety(int y)
{
_y = y;
cout<<"y = "<<_y<<endl;
}
private:
int _z;
void setz(int z)
{
_z = z;
cout<<"z = "<<_z<<endl;
}
};
class B:public A
{
public:
B()
{
cout<<"This is class B"<<endl;
}
};
int main(int argc, char const *argv[])
{
/* code */
B b1;
b1._x = 5;
b1.setX(9);
b1._y = 5; //报错 子类对象不可访问
b1.sety(9); //报错 子类对象不可访问
b1._z = 5; //报错 子类对象不可访问
b1.setz(9); //报错 子类对象不可访问
return 0;
}
class A
{
public:
int _x;
void setX(int x)
{
_x = x;
cout<<"x = "<<_x<<endl;
}
protected:
int _y;
void showy() //子类内部模块可以访问
{
cout<<"y = "<<_y<<endl;
}
private:
int _z;
void setz(int z)
{
_z = z;
cout<<"z = "<<_z<<endl;
}
};
class B:public A
{
public:
B()
{
cout<<"This is class B"<<endl;
}
void B_sety(int y)
{
_y = y;
showy();
}
};
int main(int argc, char const *argv[])
{
/* code */
B b1;
b1._x = 5;
b1.setX(9);
b1.B_sety(10);
return 0;
}
那么私有继承和保护继承也就如表所示。
对单个类来讲,私有成员与保护成员没有什么区别。从继承的访问规则角度来看,保护成员真有双重角色:在类内层次中,它是公有成员;在类外,它是私有成员。由于保护成员“真有这种特殊性,所以如果合理利用,就可以在类的复杂层次关系中为共享访问与成员隐藏之间找到一个平衡点,既能实现成员隐藏,又能方便继承,从而实现代码的高效重用和扩充。
多继承
一般格式
class <派生类名>:<继承方式><基类名1>,...,<继承方式><基类名n>
{
...
}
二义性
1. 调用不同基类的相同成员时可能出现二义性
#include <iostream>
using namespace std;
class B
{
public:
void seta(int x)
{
a = x;
}
void show()
{
cout<<a<<endl;
}
private:
int a;
};
class C
{
public:
void setb(int x)
{
b = x;
}
void show()
{
cout<<b<<endl;
}
private:
int b;
};
class D :public B,public C
{
;
};
int main(int argc, char const *argv[])
{
D d1;
d1.seta(2);
d1.show(); //出现二义性,报错
d1.setb(4);
d1.show(); //出现二义性,报错
return 0;
}
使用作用域运算符 修改:
d1.seta(2);
d1.B::show();
d1.setb(4);
d1.C::show();
2. 访问公共基类的成员时可能出现二义性
#include
using namespace std;
class A
{
protected:
int val;
};
class B : public A
{
public:
void setb(int x)
{
val = x;
}
};
class C : public A
{
public:
void setc(int x)
{
val = x;
}
};
class D :public B,public C
{
public:
void show()
{
cout<<val<<endl; //含义不清,报错 ,可以使用 域运算符解决。
}
};
int main(int argc, char const *argv[])
{
D d1;
d1.setc(2);
d1.show();
d1.setb(4);
d1.show();
return 0;
}
虚基类
虚基类,就是为了解决二义性问题,是得公共基类在他的派生类对象中只产生一个基类子对象。
#include
using namespace std;
class A
{
protected:
int val;
};
class B :virtual public A
{
public:
void setb(int x)
{
val = x;
}
};
class C : virtual public A
{
public:
void setc(int x)
{
val = x;
}
};
class D :public B,public C
{
public:
void show()
{
cout<<val<<endl;
}
};
int main(int argc, char const *argv[])
{
D d1;
d1.setc(2);
d1.show();
d1.setb(4);
d1.show();
return 0;
}