从“派生类不能访问基类对象的protected成员”开始讨论各类成员的“可见性”

时间:2022-09-07 22:17:17

一、派生类 不能通过 基类对象 访问 基类的protected成员

派生类 不能通过 基类对象 访问 基类的protected成员,如果能,不就成了public了吗?

所以“不仅派生类不能通过基类对象访问其protected成员,其他类也不能通过基类对象访问基类的protected成员”。
补充几句:派生类本身可以访问基类的protected成员,将其视为自身的成员。

   如果不在派生类中,派生类对象就不可以访问基类的protected成员。

   感觉“类的对象” 这一概念是针对用户级别的,用户当然不能访问类的protected成员和private成员。

#include <iostream>  
using namespace std;  
  
class Base{  
public:

	Base(){
		base_i=1;
		base_j=2;
	}

	virtual int geti(){
		return base_i;
	}
	int get_j( const Base & b){//同类之间, 可以通过基类对象 访问 基类的private。
		return b.base_j;
	}

protected:  
    int base_i;   
private:
	int base_j;
};  
  
class Derived: public Base{
public:  

    Derived(){  
        base_i = 10;//基类的protected成员现在是派生类的一部分,
					//派生类访问的是“属于派生类的继承自基类”的成员
    }
	
	Derived(int i){
		base_i=i;
	}

	int geti(){
		return base_i;
	}

/*	

  void setj( Derived &d){//出错,派生类试图 通过 基类对象 访问 基类的private。
		d.base_j=11111;
	}
	
*/


	void print_base_i(const Derived &d){//派生类函数中,派生类对象 可以 访问基类的protected成员
			cout<<d.base_i<<endl;
	}
	
/*
	void print_base_i_2(const Base& b){//出错,基类对象 不能 访问 基类的protected成员。
		cout<<b.base_i<<endl;
	}
	
*/

};  



int main(){  

    Base b,b2;
	cout<<b.geti()<<endl;//0 没有问题,基类的构造函数将base_i赋值为0;
	cout<<b2.get_j(b)<<endl;//同类之间可以互相访问对方的private


	Base *pb=new Derived;
	cout<<pb->geti()<<endl;//10,派生类本身可以直接访问基类的protected成员,通过调用Derived()将base_i赋值为10

/*	
	Derived d0;
	cout<<d0.base_i<<endl;
*/

	Derived d1(100);//base_i==100,派生类本身可以访问基类的protected成员,通过调用Derived(int i)将base_i赋值为100
	Derived d2(1000);//base_i==1000,派生类本身可以访问基类的protected成员,通过调用Derived(int i)将base_i赋值为1000

	d2.print_base_i(d1);//100, 派生类对象d1可以访问基类的protected成员base_i.
	d1.print_base_i(d2);//1000, 派生类对象d1可以访问基类的protected成员base_i.

    return 0;             
}  


二、只有在派生类中才可以通过派生类对象访问基类的protected成员。 

#include <iostream>  
#include <vector>  
#include <iterator>   
#include <algorithm>  
#include <numeric>  
using namespace std;  
  
class Base   
{  
public:
	Base(){
		i=1;
	}
	
	int  BaseGetI(){
		return i;
	}
protected:  
    int i;  

private:
	int j;
          
};  
  
class Derived: public Base  
{     
public:
	Derived(){//派生类成员函数对基类的protected成员可以直接访问
		i=2;
		k=3;
		///j=8; 派生类成员函数对基类的private成员没有访问权限
	}
	int DerivedGetI(){
		return i;
	}
	int DerivedGetK(){
		return k;
	}
    void fun(Derived &d)  
    {  
        d.i = 4;        //只有在派生类中才可以通过  派生类对象  访问  基类的protected成员
		d.k=5;			//派生类成员函数可以访问派生类对象的private成员
    }
	void fun2(Base &b){
		//b.i=6;//派生类成员函数不能通过 基类对象 访问 基类的protected成员。
		//b.j=7;//更不可能访问private
	}
private:
	int k;
};  
  
int main()  
{  

	Base b;
	cout<<b.BaseGetI()<<endl;

    Derived d,d2;
	cout<<d.DerivedGetI()<<endl;
	cout<<d.DerivedGetK()<<endl;
	
	d2.fun(d);
	cout<<d.DerivedGetI()<<endl;
	cout<<d.DerivedGetK()<<endl;

	d2.fun2(b);
	cout<<b.BaseGetI()<<endl;

    return 0;             
}  


三、各类数据对于 类和类对象可见性

1) 基类成员对派生类都是:共有和保护的成员是可见的,私有的的成员是不可见的。
2) 基类成员对派生类的对象来说:要看基类的成员在派生类中变成了什么类型的成员。
   如:私有继承时,基类的共有成员和私有成员都变成了派生类中的私有成员,
   因此对于派生类中的对象来说基类的共有成员和私有成员就是不可见的。

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

四、在类作用域中,同类对象可以访问其private成员

#include <iostream>
using namespace std;

class A{
public:
    A(int i_,int j_)
    {
        i=i_;
        j=j_;
    }
    void disp(A &a)
    {
        cout<<a.i<<endl<<a.j<<endl;
    }

private:
    int i;
protected:
    int j;
};

int main(int argc, char* argv[])
{
    A a(123,456);
    A b(789,543);
    a.disp(b);
    b.disp(a);

    return 0;
}


五、总结

我们其实可以这样看待类和对象:
类是将数据成员和进行于其上的一系列操作(成员函数)封装在一起,注意:成员函数可以操作数据成员(可以称类中的数据成员为泛数据成员)!
对象是类的实例化,怎样理解实例化?其实每一个实例对象都只是对其中的数据成员初始化,内存映像中每个对象仅仅保留属于自己的那份数据成员副本。而成员函数对于整个类而言却是共享的,即一个类只保留一份成员函数。
那么每个对象怎样和这些可以认为是“分离”的成员函数发生联系,即成员函数如何操作对象的数据成员?记住this指针,无论对象通过(.)操作或者(->)操作调用成员函数,编译时刻,编译器都会将这种调用转换成我们常见的全局函数的形式,并且多出一个参数(一般这个参数放在第一个),然后将this指针传入这个参数。于是就完成了对象与成员函数的绑定(或联系).
实例化后就得到同一个类的多个不同的对象,既然成员函数共享的,那么成员函数就可以操作对象的数据成员。
问题是现在有多个对象,成员函数需要知道操作的是哪个对象的数据成员?
比如有对象obj1和obj2,都属于A类,A类有public成员函数foo()
如果obj1调用该函数,编译时会给foo函数传入this指针,obj1,foo中操作obj1自身的成员就不用任何修饰,直接访问,因为其中的数据成员自动根据this指针找到。
如果obj1调用该函数,同样可以访问同类的其他对象的数据成员!那么你需要做的是让foo函数知道是同类对象中哪个对象的数据成员,一个解决办法是传入同类其他对象的指针或引用,那么就可以操作同类其他对象的数据成员。
foo(A &obj)
这样定义,然后调用:
obj1.foo(obj2)
就可以在obj1访问obj2的数据成员,而无论这些数据成员是private还是protected

搬出C++ Object Model,可以画出各个对象的内存map就可以更清晰的看出:

总结:C++的访问修饰符的作用是以类为单位,而不是以对象为单位

通俗的讲,同类的对象间可以“互相访问”对方的数据成员,只不过访问途径不是直接访问.
步骤是:通过一个对象调用其public成员函数,此成员函数可以访问到自己的或者同类其他对象的public/private/protected数据成员和成员函数(类的所有对象共用),而且还需要指明是哪个对象的数据成员(调用函数的对象自己的成员不用指明,因为有this指针;其他对象的数据成员可以通过引用或指针间接指明)

参考文献:http://www.cnblogs.com/chio/archive/2007/06/11/779408.html