您的位置:首页 > 其它

小解继承!!!(公有继承,私有继承,保护继承)

2016-07-15 13:13 316 查看
1,关于继承,公有继承,私有继承,保护继承

2,牛客网的题:对于protected成员,下面说法错误的是:()

继承:是面向对象程序设计的一个重要机制,该机制自动地为一个类提供来自另一个类的操作和数据结构,这使得

            程序员只需在新类中定义已有类中没有的成员来建立新类。也就是说:新类不但可以共享原有类的属性,

            并且具有新的特性,这样就形成了类的层次。

单继承和多继承:

单继承:如果一个派生类只有一个基类                                  多继承:同时有多个基类

单继承可以看成是多继承的一个最简单特例,而多继承可以看成是多个单继承的组合。

     

                         


单继承:

class  派生类:继承方式  基类名
{
派生类成员定义;
}


基类:必须在声明派生类之前已经声明过,不然的话,会导致编译错误。

继承方式:public(共有继承),private(私有继承),protected(保护继承)

如果省略,系统将默认为私有继承。。。。。。。。

公有继承:

当类的继承方式为公有继承时,基类中的公有(public)成员和保护(protected)成员的访问权限在派生类中保持不变,而基类的私有成员不可访问,也就是说:基类的公有成员和保护成员被派生类继承过来作为派生类的公有和保护

成员,而基类的私有成员在派生类中不能直接使用。

程序1:

#include <iostream>
using namespace std;

class A
{
private:
int y;          //私有成员
protected:
int x;          //保护成员
public:
void setx(int m)      {x = m;}
void sety(int n)      {y = n;}
int getx()
{       return x;}
int gety()
{       return y;}
};

class B:public A
{
public:
int getsum()
{
return x + gety();
}
};

int main()
{
B b;
b.setx(5);
b.sety(8);
cout<<"X = :"<<b.getx()<<endl;
cout<<"X + Y = :"<<b.getsum()<<endl;
}


运行结果:



 基类A派生出新的B类,继承方式是公有继承。在基类A中声明了数据成员和成员函数,派生类B继承基类A的所有成员

(缺省的构造和析构函数除外),从而实现了代码的重用;同时,声明了自身的成员函数getsum(),

在派生B类中,实际所拥有的成有就是从基类继承过来的成员与派生类新定义的成员的总和。。。。

派生类B的内存布局是这个样子的!!!!



在布局上,b对象的最初部分是A数据成员,指向b的this指针也就指向A对象的指针。由此可以看出,b对象中包含有A

对象部分

在实现派生类B的成员函数getsum时,直接访问从基类A继承来的保护成员x,但基类A的私有成员y,只能通过基类

的公有成员函数gety()间接完成,若直接访问y,那么会出现编译错误

因为:公有继承模式下,基类的私有成员不可访问。

私有继承:基类中的公有成员和保护成员都将以私有成员身份出现,基类的私有成员同样不可访问。

保护继承:无论私有继承还是公有继承,派生类是无权直接访问它的基类的私有成员,派生类只能通过调用基类的成

员函数来实现对于基类私有成员的访问。这对于频繁访问基类私有成员的派生类是十分方便的。为此,引入保护成员。保护成员可以被派生类的成员函数访问,但是对于外界是隐藏起来的,外部函数是不能访问它的。。。。

言外之意就是:对象可以直接访问类中的公有成员,但是,不可以访问保护成员

程序2:

#include <iostream>
using namespace std;

class A
{
private:
int y;          //私有成员
protected:
int x;          //保护成员
public:
void setx(int m)      {x = m;}
void sety(int n)      {y = n;}
int getx()
{       return x;}
int gety()
{       return y;}
};

class B:public A
{
public:
int getsum()
{
return x + gety();
}
};

int main()
{
B b;
b.x = 5;
}


本程序相对于前面而言,并没有什么大的变化,只是对象简单的调用了保护成员x

编译结果:



可以看出,这里编译出错了。。。。。。。。。,外部函数的非法访问

程序3:

#include <iostream>
using namespace std;

class A
{
private:
int y;          //私有成员
public:              //只改变了这里,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
int x;          //保护成员
public:
void setx(int m)      {x = m;}
void sety(int n)      {y = n;}
int getx()
{       return x;}
int gety()
{       return y;}
};

class B:public A
{
public:
int getsum()
{
return x + gety();
}
};

int main()
{
B b;
b.x = 5;
}


同样的,这里我们只是改变了x为公有成员,,,,,,

编译完全正确。。。。。。。。。

总结:

1,基类成员对派生类都是:公有和保护的成员是可见的,私有的的成员是不可见的

2,[b]基类成员对派生类的对象来说:要看基类的成员在派生类中变成了什么类型的成员。如:私有继承时,基类[/b]

[b]      的公有成员和私有成员都变成了派生类中的私有成员,因此对于派生类中的对象来说基类的公有成员和私有[/b]

[b]      成员就是不可见的。[/b]



对于公有继承方式

(1) 基类成员对其对象的可见性:

公有成员可见,其他不可见。这里保护成员同于私有成员。

(2) 基类成员对派生类的可见性:

公有成员和保护成员可见,而私有成员不可见。这里保护成员同于公有成员。

(3) 基类成员对派生类对象的可见性:

公有成员可见,其他成员不可见。

所以,在公有继承时,派生类的对象可以访问基类中的公有成员;派生类的成员函数可以访问基类中的公有成员和保护成员。这里,一定要区分清楚派生类的对象和派生类中的成员函数对基类的访问是不同的。

对于私有继承方式
(1) 基类成员对其对象的可见性:

公有成员可见,其他成员不可见。

(2) 基类成员对派生类的可见性:

公有成员和保护成员是可见的,而私有成员是不可见的。

(3) 基类成员对派生类对象的可见性:

所有成员都是不可见的。

所以,在私有继承时,基类的成员只能由直接派生类访问,而无法再往下继承。

对于保护继承方式
这种继承方式与私有继承方式的情况相同。两者的区别仅在于对派生类的成员而言,对基类成员有不同的可见性。



#include<iostream>
using namespace std;
//////////////////////////////////////////////////////////////////////////
class A       //父类
{
private:
int privatedateA;
protected:
int protecteddateA;
public:
int publicdateA;
};
//////////////////////////////////////////////////////////////////////////
class B :public A      //基类A的派生类B(共有继承)
{
public:
void funct()
{
int b;
b=privatedateA;   //error:基类中私有成员在派生类中是不可见的
b=protecteddateA; //ok:基类的保护成员在派生类中为保护成员
b=publicdateA;    //ok:基类的公共成员在派生类中为公共成员
}
};
//////////////////////////////////////////////////////////////////////////
class C :private A  //基类A的派生类C(私有继承)
{
public:
void funct()
{
int c;
c=privatedateA;    //error:基类中私有成员在派生类中是不可见的
c=protecteddateA;  //ok:基类的保护成员在派生类中为私有成员
c=publicdateA;     //ok:基类的公共成员在派生类中为私有成员
}
};
//////////////////////////////////////////////////////////////////////////
class D :protected A   //基类A的派生类D(保护继承)
{
public:
void funct()
{
int d;
d=privatedateA;   //error:基类中私有成员在派生类中是不可见的
d=protecteddateA; //ok:基类的保护成员在派生类中为保护成员
d=publicdateA;    //ok:基类的公共成员在派生类中为保护成员
}
};
//////////////////////////////////////////////////////////////////////////
int main()
{
int a;

B objB;
a=objB.privatedateA;   //error:基类中私有成员在派生类中是不可见的,对对象不可见
a=objB.protecteddateA; //error:基类的保护成员在派生类中为保护成员,对对象不可见
a=objB.publicdateA;    //ok:基类的公共成员在派生类中为公共成员,对对象可见

C objC;
a=objC.privatedateA;   //error:基类中私有成员在派生类中是不可见的,对对象不可见
a=objC.protecteddateA; //error:基类的保护成员在派生类中为私有成员,对对象不可见
a=objC.publicdateA;    //error:基类的公共成员在派生类中为私有成员,对对象不可见

D objD;
a=objD.privatedateA;   //error:基类中私有成员在派生类中是不可见的,对对象不可见
a=objD.protecteddateA; //error:基类的保护成员在派生类中为保护成员,对对象不可见
a=objD.publicdateA;    //error:基类的公共成员在派生类中为保护成员,对对象不可见

return 0;
}


牛客网的题:

对于protected成员,下面说法错误的是:()

基类可以访问从所有派生类造型(cast)成基类对象的protected成员

从派生类继承的子类里可以访问基类的protected成员

派生类可以定义一个同名的非protected成员

派生类可以访问基类对象的protected成员


分析这个题:
首先我们先看D选项:

上面所说的派生类应该只是经过一次继承,而不是经过多次继承的,因为由B选项可以看出这里提到了派生类的继承

派生类可以访问基类对象的protected成员,由上面我们分析可知:

对于protected成员,公有继承,属性不变,,,,私有继承,变为私有,,,,保护继承,属性不变,但是都可访问

关于C选项:

现在有这样一个问题:如果A类是基类,里面有一个公有成员变量x,B类继承了A,里面也新加了一个公有成员x,就

是说,基类与派生类中有一个同样的变量,那么我们调用B类的对象直接调用x的话,那么调用的是基类中的x,还是

派生类中的x呢???

(这里选用公有成员,是为了便于派生类的对象直接调用,方便)

程序4:

#include <iostream>
using namespace std;

class A
{
private:
int y; //私有成员
protected:
int x; //保护成员x,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
public:
A(int xx, int yy) {x = xx; y = yy;}
void setx(int m) {x = m;}
void sety(int n) {y = n;}
int getx()
{ return x;}
int gety()
{ return y;}
};

class B:public A
{
public:
int x; //公有成员x,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
public:
B(int xx, int yy):A(xx, yy)
{
x = xxx;
}
int getx()
{
return x;
}
};

int main()
{
B b(1,2,3);
cout<<b.getx()<<endl;;
}

运行结果:



可以看出,这里调用的是本类下的变量(前提是:如果本类中存在这个变量的话),也就是B类

程序5:

#include <iostream>
using namespace std;

class A
{
private:
int y; //私有成员
protected:
int x; //保护成员
public:
A(int xx, int yy) {x = xx; y = yy;}
void setx(int m) {x = m;}
void sety(int n) {y = n;}
int getx()
{ return x;}
int gety()
{ return y;}
};

class B:public A
{
public:
B(int xx, int yy):A(xx, yy)
{
;
}
int getx()
{
return x;
}
};

int main()
{
B b(1,2);
cout<<b.getx()<<endl;;
}
可以看出:这里面只有基类(A类)中有这个变量x,B类中并不存在,所以B类的对象调用一定是基类中的x
运行结果:



所以说:对于派生类的调用,是先在自己的类中找所调用的变量,如果没有去基类中查看,如果也没有的话,那么

去就会报编译出错!!!!!!

由此可知:c选项是正确的,,,派生类可以定义一个同名的非protected成员

关于B选项:从派生类继承的子类里可以访问基类的protected成员!!!

对于这句话,当他们的派生方式是保护继承或者公有继承的时候,是可以访问基类中的protected成员的,

而如果是私有方式继承的话,,,A为基类,B私有继承A,而C私有继承B,A里面有一个protected成员,那么经过

一次私有继承后,就相当于B里面的私有成员,而在经过一次私有继承,那么C肯定是不可能访问它的私有成员的。

关于A选项:

基类可以访问从所有派生类造型(cast)成基类对象的protected成员

派生类造型cast成基类对象,我们用的是dynamic_cast
程序:

#include <iostream>                                                                                                                             
using namespace std;

class A
{
        private:
                int y;          //私有成员
        protected:
                int x;          //保护成员
        public:
                A(int xx, int yy)     {x = xx; y = yy;}
                void setx(int m)      {x = m;}
                void sety(int n)      {y = n;}
                int getx()
                {       return x;}
                int gety()
                {       return y;}
                int getx1() //为了顺应题意,我们加上的,,,,,
                {       return x1;}
};

class B:public A
{
protected:
int x1;
public:
B(int xx, int yy, int xxx):A(xx, yy)
{
x1 = xxx;
}
int getx()
{
return x;
}
};

int main()
{
B b(1,2,3);
B *pb = &b;
A *pa = dynamic_cast<A *>(pb);
pa->getx1();
// cout<<b.getx()<<endl;;
}

结果很明显,虽然将B强行转化成了基类,但是属于B类的protected成员x1,并不在A类中,,,,,,,,,,,,
运行结果:



所以应该是这样的:派生类强制转化成基类(dynamic_cast)会做相应成员变量和函数的裁剪,仅能访问从基类继承来的部分成员

本文部分类容借鉴与(谢谢啦!!!):http://www.cnblogs.com/qlwy/archive/2011/08/25/2153584.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息