继承和派生的概念C++面向对象设计的4个主要特点:抽象、封装、继承和多态。其中继承性是面向对象程序设计最重要的特性之一,使软件有了可重用性。继承提供了在已有类的基础上开发出新类的机制,可以节省重复代码的编写工作,是软件重用的基础。 继承是一个新类从已有的类那里获得已有的特性,保留利用原有的类的功能。派生是添加新的成员和功能,意思是吸收基类成员、改造基类成员、添加新的成员。默认情况下派生类包含了全部基类函数中除构造函数和析构函数之外的所有成员,C++11规定可以用using语句继承基类构造函数。 类之间的关系可以分为:has-A,uses-A 和 is-A。 has -A是指包含关系,用以描述一个类由多个基类构成;实现has -A关系用类成员表示,意思是一个类中的数据成员是另一种已经定义的类。 users-A是指一个类部分的使用另一类;通过类之间成员函数进行相互联系,定义友元或对象参数实现。 is-A是指继承,关系具有传递性,不具有对称性。C++有3种继承方式:公有继承、保护继承和私有继承;其中公有继承是建立一种is-A关系,即派生对象也是一个基类对象,可以对基类对象执行任何操作,也可以对派生类对象执行操作。 继承和派生的性质2.1 继承和派生定义 继承的定义如图所示: 派生类的定义如图所示: 注意点: - 派生类拥有基类的所有成员变量和成员函数。
- 派生类可以拥有基类没有的方法和属性。
- 派生类就是一种特殊的基类。
- 派生类对象可以当作基类对象使用。
2.2 继承的方式 在C++中,有两种继承方式:单一继承和多重继承。单一继承定义派生类的一般格式: class <派生类名>: <继承方式> <基类名>
{
[private: // 私有成员说明
...]
[public: // 公有成员说明
...]
[protected: // 保护成员说明
...]
} ;
举个例子: #include <iostream>
using namespace std;
// 基类
class Shape
{
public:
void set_params(int wid, int hig)
{
width = wid;
height = hig;
}
protected:
int width;
int height;
};
// 派生类
class Rectangle : public Shape
{
public:
int get_area()
{
return (width * height);
}
};
int main()
{
Rectangle Rect;
Rect.set_params(4, 10);
// 输出对象的面积
cout << "Total area: " << Rect.get_area() << endl;
return 0;
}
例子中派生类Rect可以直接调用基类的成员函数。多重继承定义派生类的一般格式: class <派生类名>: <继承方式1> <基类名1>, <继承方式2> <基类名2>,…
{ //以下定义派生类新成员
[private: // 私有成员说明
... ]
[public: // 公有成员说明
... ]
[protected: // 保护成员说明
... ]
} ;
举个例子: #include <iostream>
using namespace std;
// 基类 Shape
class Shape
{
public:
void set_params(int wid, int hig)
{
width = wid;
height = hig;
}
protected:
int width;
int height;
};
// 基类 PaintCost
class PaintCost
{
public:
int get_cost(int area)
{
return area * 70;
}
};
// 派生类
class Rectangle : public Shape, public PaintCost
{
public:
int get_area()
{
return (width * height);
}
};
int main()
{
Rectangle Rect;
Rect.set_params(4, 10);
int area = Rect.get_area();
// 输出对象的面积
cout << "Total area: " << area << endl;
// 输出总花费
cout << "Total paint cost: $" << Rect.get_cost(area) << endl;
return 0;
}
例子中派生类Rect可以直接调用两个基类的成员函数。 派生类的访问控制C++中的继承方式会影响派生类的对外访问属性public、protected 或 private,不同类型的继承时,遵循以下几个规则: 公有继承(public):基类的public和protected成员的访问属性在派生类中保持不变;基类的private成员不可直接访问;派生类的成员函数,可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员。通过派生类创建的对象,只能访问public成员(包括基类的public成员)。 保护继承(protected): 基类的public和protected成员:都以protected身份出现在派生类中;基类的private成员不可直接访问;派生类的成员函数,可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;通过派生类创建的对象,不能访问基类的任何成员。 私有继承(private):基类的public、protected、private成员,都以private身份出现在派生类中;派生类的成员函数,可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;通过派生类创建的对象,不能访问基类的任何成员。 可以根据访问权限总结出不同的访问类型,如下所示: 一个派生类继承了所有的基类方法,但下列情况除外: - 基类的构造函数、析构函数和拷贝构造函数。
- 基类的重载运算符。
- 基类的友元函数。
举个例子: #include <iostream>
using namespace std;
// 基类 Shape
class Shape
{
public:
void set_params(int wid, int hig)
{
width = wid;
height = hig;
}
protected:
int width;
int height;
private:
int angle;
};
// 派生类1
class Rectangle1 : public Shape
{
public:
int get_area()
{
return (width * height);
}
int get_angle()
{
//return angle;//无法访问private成员
}
};
// 派生类2
class Rectangle2 : protected Shape
{
public:
int get_area()
{
return (width * height);
}
int get_angle()
{
//return angle;//无法访问private成员
}
};
// 派生类3
class Rectangle3 : private Shape
{
public:
int get_area()
{
return (width * height);
}
int get_angle()
{
//return angle;//无法访问private成员
}
};
int main()
{
Rectangle1 Rect1;
Rect1.set_params(4, 10);
int area = Rect1.get_area();
// 输出对象的面积
cout << "Total area: " << area << endl;
Rectangle2 Rect2;
//Rect2.set_params(4, 10);//无法访问set_params函数
Rectangle3 Rect3;
//Rect3.set_params(4, 10);//无法访问set_params函数
return 0;
}
从例子中可以看出Rectangle2和Rectangle3派生类都不能访问基类成员函数set_params,因为是protected和private继承方式。
|