您的位置:首页 > 其它

7、继承

2016-02-25 16:06 232 查看

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);
}


[/code]

    都可以打印出  a = 100;,这里就涉及到继承的方式的问题:

class 子类名 : 继承的方式 父类名
{
}


[/code]

    当没有指定 继承的方式(public,private)的话,那么就是默认为私有的继承。

继承的权限:

继承的方式


public        父类在子类中,保持原有的访问的级别,子类可以访问父类的共有成员,私有成员不能被访问


private       父类在子类中,全部变为private的访问级别,那么子类不可以访问父类所有的成员


[/code]

    一般来说,我们都是 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


[/code]





继承成员对外的访问的属性: MAX(继承的方式,父类的访问的级别)

继承访问级别设置的原则:


需要被外接(对象)访问的成员直接设置为: public

只能在类的内部被访问的成员设置为 : private

只能在当前类和子类中访问的成员设置为 : protected



继承中的构造和析构函数:

    子类和父类的继承,那么子类已经是继承了父类所有的成员函数和成员变量(除了构造函数和析构函数、拷贝构造函数、operator函数、友元函数没有被继承、)。

子类的对象构造的时候,会调用父类的构造函数。父类的构造函数完成父类的构造,而子类的构造函数则是完成自己新增的成员进行初始化;因此析构的函数也是一样的,子类的就析构自己的就可以,继承的东西,就让父类的析构函数自己去完成清理的工作。

class Parent
{
public:
Parent();
~Parent();
private:
};
Parent::Parent()
{
cout << "ia= am parent gouzao" << endl;
}
Parent::~Parent()
{
cout << "ia= am parent xigou" << endl;
}
class Child : public Parent
{
public:
Child ();
~Child ();
private:
};
Child :: Child()
{
cout << "ia= am Child gouzao" << endl;
}
Child ::~Child()
{
cout << "ia= am Child xigou" << endl;
}
void run()
{
Child c1;
}
int main()
{
run();
while (1);
}
输出的结果:
ia= am parent gouzao
ia= am Child gouzao
ia= am Child xigou
ia= am parent xigou




    可见,子类对象创建的时候,是先自动调用父类的构造函数,执行完毕之后再指定子类的构造函数;虚构函数是先析构子类的构造函数,然后再执行父类的析构函数;同时可以看到,析构函数是构造函数的完全相反地执行。

继承与组合:

    组合就是自身的成员是其他类的对象,这个就叫组合,那么构造函数和析构函数的执行的顺序,

class Obj
{
public:
Obj(char *s)
{
cout << "obj" << " " << s << endl;
}
};
class Parent : public Obj
{
public: // 初始化列表
Parent(char *s) : Obj(s)
{
cout << "parent" << " " << s << endl;
}
};
class Child : public Parent
{
private:
Obj o1; // 来气其他类的对象
Obj o2; // 两个对象,那么就是两次
public:
Child() : o1("o1"), o2("o2"), Parent("paren from")
{
cout << "child" << endl; // 最后才执行自己
}
};
int main()
{
Child c1;
while (1);
}
执行结果:
obj paren from // 先父母的父母
parent paren from // 接着父母
obj o1  // 再别人
obj o2 // 再别人
child  // 最后自己




   构造函数执行的顺序: 先父母,在别人,最后自己;首先可以看到,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);


}


[/code]

    输出的结果是: f B,当子类与父类函数名相同的时候,那么子类是没有办法调用父类的同名函数的,因为父类的同名函数被编译器做隐藏的处理,
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: