赞
踩
从已有的类产生新的类叫派生,新的类叫子类(派生类),已有类叫父类(基类),
称子类继承父类;或父类派生出子类。派生与继承是同一种意义的两种表述。
C++利用继承来实现代码的可重用。子类继承父类的全部成员(除了构造函数与析构函数);
则子类对象可以调用父类的函数而不必重新定义函数与变量。
is a 的关系是一种属于的关系,如:学生是人,老师是人。校长是人。则可以把
人设计成为基类把学生,老师,校长设计成为派生类。
has a 的关系是一种拥有关系,如:电脑有: CPU,硬盘,显卡,内存等等。则可以
设计 CPU 硬盘 显卡 内存 等等为基类。电脑为派生类,由各种组件组成。
派生类:
class 派生类名 :继承方式 基类名
{
正常声明;
}
基类 man class man{ char* sex; int tall; char *name; public: void showData(char _name[],char _sex[],int _tall){ sex=new char[strlen(_sex)+1]; strcpy(sex,_sex); tall=_tall; name=new char[strlen(_name)+1]; strcpy(name,_name); cout<<"名字:"<<name<<" 性别:"<<sex<<" 身高:"<<tall<<endl; } }; 派生类 student class student:public man { }; int main() { student st; st.showData("小明","男",180); return 0; }
如果需要实现老师类,校长类,则不需要重复实现函数 showdata(),都继承至父类就好了
示例说明:
存在以下基类:
class base{
public:
int pub;
protected:
int pro;
private:
int pri;
}
派生类在不同方式继承下,三个数据的可见性表:
继承方式 | public | protected | private |
---|---|---|---|
pub | public | protected | private |
pro | protected | protected | private |
pri | 不可见 | 不可见 | 不可见 |
类内的权限控制:
public | protected | private |
---|---|---|
对外开放 | 子类可见 | 仅本类内 |
派生类要调用基类成员必须对基类进行构造
基类成员的初始化还是由基类的构造函数完成。然后再执行子类构造。
语法:
派生类名::派生类名(参数总表)
:基类名(参数表),内嵌子对象(参数表)
{
派生类新增成员的初始化语句; //也可出现地参数列表中
}
需要注意的是:在C++类的模块中系统提供很多默认的东西。这里也不例外。当你都不实现采用系统提供的构造函数时,不需要显式调用基类构造函数。但如果父类没有默认构造函数;则需要上面的格式实现派生类构造器。
构造顺序:
派生类的构造,会先调用基类的构造,如果派生类的数据中存在其他类对象作为数据成员
则构造顺序为:基类构造->派生类内数据对象构造->派生类构造
** **:当派生类构造完成则该派生类对象已经全部初始化,所以基类与类内对象必须提前
初始化。
析构顺序:
析构顺序为:派生类析构->派生类内数据对象析构->基类析构
个人理解:当变量的存在空间销毁时自动回收,则当派生类对象析构时,带动其他两个析构。
例子:
class birthday{ public: birthday(){ cout<<birthday<<endl; } ~birthday(){ cout<<"~birthday()"<<endl; } } class man{ public: man(){ cout<<"man()"<<endl; } ~man(){ cout<<"~man()"<<endl; } }; class student:public man { public: student(){ cout<<"student()"<<endl; } ~student(){ cout<<"student()"<<endl; } };
测试:
int main() {
student st;
//st.showData("小明","男",180);
return 0;
}
结果:
派生类中的默认拷贝构造器会调用父类中默认或自实现拷贝构造器,若派生类中自实现拷
贝构造器,则必须显示的调用父类的拷贝构造器
自实现使用格式可参考以下实例
class Student{
public:
Student(const Student & another)
{
name = another.name;
num = another.num;
sex = another.sex;
}
}
class Graduate{
Graduate(const Graduate & another)
:Student(another),salary(another.salary){ }
}
这里之所以可以直接传派生类对象给基类拷贝构造函数,是因为继承有个赋值兼容的机制
赋值兼容是指可以派生类对象可以隐式转换为基类对象,这一点在拷贝构造,友元中都有相关应用。
在继承中,编译器都会提供 派生类与基类的默认赋值运算符重载,关于默认可参考day4 C++复制构造、赋值运算符重载、this指针,类对象内存,赋值运算符重载跟普通成员函数一样都可以被继承,同时,系统提供的默认会自动调用基类的赋值运算符重载,但如果自实现了派生类的赋值运算符重载,则需要主动显式地调用基类重载。
自实现使用格式可参考以下实例
class student{ private: string name; int num; char sex; public: student& opreator=(const student& another){ if(this == &another) return *this; this->name = another.name; this->num = another.num; this->sex = another.sex; return * this; } } class Graduate{ private: int salary; public: Graduate & operator=(const Graduate & another){ if(this == &another) return *this; Student::operator =(another); this->salary = another.salary; return * this; } }
友元并不能继承,但是有些时候需要使用基类的友元。这时候可以借助赋值兼容把子类对象强转成为基类对象。
shadow现象是指派生类对象中出现了与基类的同名函数,注意这里单单是因为同名派生类隐藏基类的同名成员。如果需要访问这些被隐藏的成员,需要加上基类名作用域。
格式:基类名::成员名;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。