c++学习笔记(11.继承的构造与析构)

来源:互联网 发布:手机淘宝如何关闭店铺 编辑:程序博客网 时间:2024/06/08 21:26

本节知识点:

1.继承的概念:

   a.面向对象中的继承指类之间的父子关系,子类拥有父类的所有成员变量和成员函数子类就是一种特殊的父类子类对象可以当作父类对象使用子类可以拥有父类没有的方法和属性

2.类的protected属性成员:

   a.protected成员可以在本类和子类中被访问,但不能在外界被访问。protected成员的访问权限介于public和private之间。

3.c++中的访问级别与继承:

   a.继承时的访问级别设定会影响到成员的访问级别,c++中class的默认继承为private继承
   b.private继承的子类拥有父类的所有成员,private继承使得父类的所有成员在子类中变成private成员
   c.public继承,父类成员在子类中保持原有访问权限。private继承,父类成员在子类中变成为private成员。protected继承,父类中访问权限比protected高的,保持原有权限,其余的访问权限变成protected。
    d.最长用的继承方式为,public继承。类的成员常用protected属性和public属性。

4.类成员访问级别设置的原则:

   a.需要被外界访问的成员直接设置为public
   b.只能在当前类中访问的成员设置为private
   c.只能在当前类和子类中访问的成员设置为protected
   d.private成员在子类中依然存在,但是却无法访问到
示例代码:
#include <iostream>using namespace std;class test{private:int a;protected:int b;public:int c;test(){a = 1;b = 2;c = 3;//cout << "test()" <<endl;}void print(){cout << a << " " << b << " " << c <<endl; }};class t1 : public test{};class t2 : protected test{public:void fun(){t2 q;q.b =  10;q.print(); }};int main(){t1 t;t.c = 12;t.print();t2 p;p.fun();//p.b = 10;  //因为b是protected属性的 只能在本类和子类中使用 //p.print();  //因为p是protected继承方式 所有print为protected属性 不能在外界使用 return 0;}

5.子类与父类的赋值兼容性原则:

   a.子类对象可以当作父类使用,子类就是特殊的父类
   b.子类对象可以直接赋值给父类对象
   c.子类对象可以直接初始化父类对象
   d.父类指针可以直接指向子类对象
   e.父类引用可以直接引用子类对象
示例代码:
#include <iostream>using namespace std;class test{protected:int a; public:void print(){cout << "test()" <<endl;}};class test1 : public test{};int main(){test1 a1;test t1 = a1; //子类对象可以给父类对象初始化t1.print(); test t2;t2 = a1; //子类对象可以给父类对象赋值t2.print();test* t3 = &a1; //父类对象指针指向子类对象 t3->print();test& t4 = a1;  //父类引用可以引用子类对象 t4.print();return 0;}  

6.继承与构造析构:

   a.类在c++编译器的内部可以理解为结构体子类是由父类成员叠加子类新成员得到的

   b.继承与构造:在子类对象构造的时候,需要调用父类的构造函数对其继承得来的成员进行初始化,如图

   c.继承与析构:在子类对象析构的时候,需要调用父类析构函数对其继承得来的成员进行初始化,如图

示例代码:
#include <iostream>using namespace std;class test{protected:int a; public:test(){cout << "test()" << endl;}~test(){cout << "~test()" <<endl;}};class test1 : public test{public:test1(){cout << "test1()" << endl;}~test1(){cout << "~test1()" << endl;}};int main(){test1 t1;return 0;}  
注意:第一,子类对象在创建时会首先调用父类的构造函数
           第二,父类构造函数执行结束后,执行子类的构造函数
           第三,当父类的构造函数有参数时,需要在子类的初始化列表中显示调用
           第四,析构函数调用的先后顺序与构造函数相反
示例代码:
#include <iostream>using namespace std;class gparent{public:gparent(char* s) {cout << "gparent() " << s << endl;}};class parent : gparent{public:parent(char* s) : gparent(s)  {cout << "parent() " << s << endl;}};class child : parent{protected:parent p1;parent p2;public:/*这条语句有点意思  本来说初始化列表在构造函数前面执行  但是在初始化列表中 竟然可以使用构造函数的形参值    所以看来初始化列表 和 构造函数的关系挺暧昧    p1(s)的意思是 初始化p1对象 如何初始化的    就是调用parent类的构造函数 即parent p1(s);     p1(" p1 ")的意思也是 初始化p1对象  也是调用parent类的构造函数 即parent p1(" p1 "); */child(char* s) : parent(s) , p1(" p1 ") ,p2(" p2 ") {cout << "child() " << s << endl;}};int main(){child c1("hello world"); return 0;}
注意:第一,初始化列表并不是完全在构造函数调用的前面执行的,初始化列表中可以使用构造函数的形参,如: parent(s) ,  p1(s)
           第二,在初始化列表中,初始化其他类的对象的时候,其实是在调用其他类的构造函数,如:p1(s) 就是 parent p1(s)           p1(" p1 ")  就是   parent  p1(" p1 ")
           第三,对于这些构造函数的调用顺序,要遵守  先父母,后客人,再自己  的原则

7.子类与父类中的同名成员变量:

    a.当子类成员变量与父类成员变量同名时,子类依然从父类继承同名成员
    b.在子类中通过作用域分别符号 :: 进行同名成员区分
    c.同名成员存储在内存中的不同位置
    d.如果在子类中不用作用域分别符号 来区分同名成员变量,默认的成员变量是子类的成员变量
示例代码:
#include <iostream>using namespace std;class test{protected :int a;int b;public :};class t : test{protected :int a;int b;public :void fun(){a = 12;b = 11;cout << a << " " << b << endl;cout << test::a << " " << test::b << endl;cout << t::a << " " << t::b << endl;}};int main(){t t1;t1.fun();return 0;}


3 0