7、继承
1.继承
儿子继承父亲的遗产,儿子拥有父亲所有的成员变量和成员函数。儿子也可以拥有父亲没有的成员变量和成员函数。
子类与父类继承的关系,
也就是说:
(1)子类拥有父类所有的成员变量和成员函数(除了构造函数和析构函数)。
(2)子类的对象可以当作父类的对象使用(认为子类是特殊的一个父类)
(3)子类可以用父类没有的成员变量和成员函数。
class Parent { public:Parent();~Parent();void pri(); private:int a; }; Parent::Parent() {a = 100; } Parent::~Parent() { } void Parent::pri() {cout << "a = " << a << endl; } class Child : public Parent // 继承父类 { }; int main() {Parent p1;p1.pri();Child c1;c1.pri();while (1); }都可以打印出 a = 100;,这里就涉及到继承的方式的问题:
class 子类名 : 继承的方式 父类名 { }当没有指定 继承的方式(public,private)的话,那么就是默认为私有的继承。
继承的权限:
继承的方式
public 父类在子类中,保持原有的访问的级别,子类可以访问父类的共有成员,私有成员不能被访问
private 父类在子类中,全部变为private的访问级别,那么子类不可以访问父类所有的成员
一般来说,我们都是 public 的方式进行继承,但是 private 成员可以被子类继承,但是不能被子类访问,所以,就有了了继承的关键字:protected
关键字 protected:
介于 private 和 public 之间,也就是说,被 protected 修饰的变量:
(1)可以在类内被访问
(2)可以被子类访问
(3)不可以被外接(通过对象,不管是父类还是子类都不可以被访问)访问
class Parent { public:Parent();~Parent();void pri(); protected: // 被保护的,子类就可以访问int a; }; Parent::Parent() {a = 100; } Parent::~Parent() { } void Parent::pri() {cout << "a = " << a << endl; } class Child : public Parent // 继承父类 { protected: // int b; public:void setDATA(int a, int b){this->a = a;this->b = b; // b 是被保护的,所以可以被子类访问 }void cintData(){cout << "a = " << a <<" "<< "b = " << b << endl;} }; int main() {Parent p1;p1.pri();Child c1;c1.setDATA(1, 2);c1.cintData();while (1); }如果不是被 protected 修饰,而是被 private 修饰的话,那么子类压根就没有权限去访问父类的 private 的成员变量,这个就不是我们想看到的,
权限的设置:
(1)需要被外接访问,则使用 public
(2)只能在类内被访问的成员的话,则是设置为 private
(3)只能在当前类内和子类中的访问的成员,则是设置为 protected
继承成员对外的访问的属性: MAX(继承的方式,父类的访问的级别)
继承访问级别设置的原则:
需要被外接(对象)访问的成员直接设置为: public
只能在类的内部被访问的成员设置为 : private
只能在当前类和子类中访问的成员设置为 : protected
继承中的构造和析构函数:
子类和父类的继承,那么子类已经是继承了父类所有的成员函数和成员变量(除了构造函数和析构函数、拷贝构造函数、operator函数、友元函数没有被继承、)。
子类的对象构造的时候,会调用父类的构造函数。父类的构造函数完成父类的构造,而子类的构造函数则是完成自己新增的成员进行初始化;因此析构的函数也是一样的,子类的就析构自己的就可以,继承的东西,就让父类的析构函数自己去完成清理的工作。
可见,子类对象创建的时候,是先自动调用父类的构造函数,执行完毕之后再指定子类的构造函数;虚构函数是先析构子类的构造函数,然后再执行父类的析构函数;同时可以看到,析构函数是构造函数的完全相反地执行。
继承与组合:
组合就是自身的成员是其他类的对象,这个就叫组合,那么构造函数和析构函数的执行的顺序,
构造函数执行的顺序: 先父母,在别人,最后自己;首先可以看到,child 继承 父母,而父母则是继承 obj,很显然必须是先执行 obj 的打印(构造函数),再执行 parent 的构造函数;接着是别人,child 里面有两个 对象作为自己的成员变量,所以就执行两次 obj 的构造函数;最后才是执行自己的 child 打印
子类和父类的成员同名的时候:
(1)子类的成员变量和父类的成员变量同名的时候:
A、子类依然继承父类同名的成员名
B、子类中通过作用域分别符 :: 来进行区分是哪一个成员
C.、同名的成员存储在内存中的不同的位置
class Parent { protected:int i; public: }; class Child : public Parent { protected:int i; public:Child(int i){Parent::i = i; // 通过作用域进行指定同名的成员变量Child::i = i + 1;}void pri(){ // 打印父类和子类的 i 值cout << "parent ::i = " << Parent::i << endl;cout << "Child ::i = " << Child::i << endl;cout << "parent i dizhi" << &(Parent::i) << endl;cout << "parent i dizhi" << &(Child::i )<< endl;} }; int main() {Child c1(5);c1.pri();while (1); }成功打印出: 5 和 6 ,而且 不同 i 的地址是不一样的,也就是说,i 是存储在不同的内存的位置;通过 类名 + ""(作用域操作符)进行区分;
(2)子类与父类的函数同名:
class Parent { public:void f(){cout << "f A" << endl;} }; class Child : public Parent { public:void f(){cout << "f B" << endl;} }; int main() {Child c1;c1.f();while (1); }while (1);
}
输出的结果是: f B,当子类与父类函数名相同的时候,那么子类是没有办法调用父类的同名函数的,因为父类的同名函数被编译器做隐藏的处理,
转载于:https://www.cnblogs.com/qxj511/p/5217361.html
总结
- 上一篇: 提高代码质量:如何编写函数
- 下一篇: 标准CSV解析