多重派生类访问基类的成员属性及C++类的封装破坏

时间:2022-09-07 21:21:07
现有如下类结构:

class A                   
{
public:

xmlNodePtr GetProp(){ return xmlNodePtr; }
};

class B
{
private:
 A m_a;
};

class C
{
private:
 B m_b;
};

class _N_Base : public C
{};

class _N_1 : public _N_Base
{
//
};

请问大家,诸如此结构的类继承,如何在不破坏 classB及各个类的封装下(或破坏尽量少)的情况下,让class _N_1方便的访问到 class A 中的成员呢(比如函数 GetProp())

这个结构只是在下举得一个例子,诸如此类情况大家是如何解决的???望大家踊跃发言

15 个解决方案

#1


对了,也可以设计一个其他的合理结构来弥补该结构的缺点,但是访问顺序是不能变的,比如Win32FileMemMap必须可以访问Win32File的成员,但是Win32File绝对不可以访问Win32FileMemMap的成员。^.^

#2


怎么没有大侠回答我的问题啊?我貌似发错地方了??(╰_╯)#

#3


friend,否则,正常手段没法访问。

#4


以下代码是非正常访问手段,但根本不通用。任何变动都有可能导致obj.fun();出问题。


class A  
{
public:

void fun(){cout<<"A"; }
};

class B
{
private:
 A m_a;
};

class C
{
private:
 B m_b;
};

class _N_Base : public C
{};

class _N_1 : public _N_Base
{
public:
void fun(){A *p = (A*)this; p->fun();}
};

int main(int argc, char *argv[])
{
_N_1 obj;
obj.fun();
return 0;
}

#5


public:

xmlNodePtr GetProp(){ return xmlNodePtr; }

大哥,看清楚了,是public方法,friend 有什么用

#6


其实你全public就可以了。封装不是一定要用语法机制来限制访问,人的自律更重要。

#7


我的意思通过程序的结构来考虑,设计出更加 合理方便的类结构,而不是通过各种诡异的手段来实现各种常理下不可达的目的。

#8


该回复于2011-11-04 17:13:22被版主删除

#9


都私有了,你为啥要访问啊。

#10


改为protected的成员数据。

#11


因为派生类需要的信息在那个基类中啊,所以要放呢,

我之所以问这个问题并不是我不知道如何访问到这个基类中的函数(要访问其实很简单《1》每个类都实现一个接口来调用自己的成员变量,但是这样如果某个类的成员变量有好多属性需要外部访问,那么使用这个成员的类就得提供好多接口来实现外部对这个类成员的访问,《2》类中的成员变量设为公有的,但是这样不就失去类的封装性及数据私有化的作用了吗)

我的意思是尽量减少对类封装性的破坏,这使矛盾的,但是我觉得肯定有一个平衡点,我目前采用的是继承。

#12


1. 正常的解决方法:用正常的办法的话,你可以不改变成员变量的属性,但你必须在各类中增加一个public成员函数,来获得那个私有成员变量。


#include <iostream>
using namespace std;
class A  
{
public:
//xmlNodePtr GetProp(){ return xmlNodePtr; }
void print_some_info() // 用这个函数代替上面那个函数做实验
{
cout << "hello, class A" << endl;
}
};

class B
{
public:
A getMemberA()
{
return m_a; // 严格地,这要求A实现拷贝构造函数
}
private:
A m_a;
};

class C
{
public:
B getMemberB()
{
return m_b; // 严格地,这要求B实现拷贝构造函数
}
private:
B m_b;
};

class N : public C
{
public:
void print_info()
{
getMemberB().getMemberA().print_some_info();
}
};

int main(void)
{
N n;
n.print_info();

return 0;
}


2. 不正常的解决办法:

#include <iostream>
using namespace std;
class A  
{
public:
//xmlNodePtr GetProp(){ return xmlNodePtr; }
void print_some_info() // 用这个函数代替上面那个函数做实验
{
cout << "hello, class A" << endl;
}
};

class B
{
private:
A m_a;
};

class C
{
private:
B m_b;
};

class N : public C
{
public:
};

int main(void)
{
N n;

((A*)((B*)(&((C)n))))->print_some_info();
        // 说明:
        // (C)n:         
        //  1. 将n由N转型为C,用static_cast也可以,那么(通过剪裁)可以得到一个C对象

        // &((C)n)     
        // 2. 取1中所得到对象的地址

        // (B*)(&((C)n))  
        // 3. C对象中的第一个成员变量是B类型的m_b,因此我们可以通这种方式得到m_b的地址

        // (A*)((B*)(&((C)n))) 
        // 4. m_b这个B对象的第一个成员变量是A类型的m_a,因此我们可以通过这种方式得到m_a的地址

        // ((A*)((B*)(&((C)n))))->print_some_info();
        // 5. 用m_a的地址去调用print_some_info()
return 0;
}

用这种不正常的方法,要求对C++对象模型比较了解才行。

#13


该回复于2011-11-07 09:15:06被版主删除

#14


要不就让成员为Protected,要不就提供Protected方法private成员,让子类提供Public接口调用Protected方法。

#15


恩,其实我仔细想了想,无非也就是层层的接口调用或是类继承这两种方法,不正常的方法不可以用,防止以后编译器的变动导致诡异的手段失效

#1


对了,也可以设计一个其他的合理结构来弥补该结构的缺点,但是访问顺序是不能变的,比如Win32FileMemMap必须可以访问Win32File的成员,但是Win32File绝对不可以访问Win32FileMemMap的成员。^.^

#2


怎么没有大侠回答我的问题啊?我貌似发错地方了??(╰_╯)#

#3


friend,否则,正常手段没法访问。

#4


以下代码是非正常访问手段,但根本不通用。任何变动都有可能导致obj.fun();出问题。


class A  
{
public:

void fun(){cout<<"A"; }
};

class B
{
private:
 A m_a;
};

class C
{
private:
 B m_b;
};

class _N_Base : public C
{};

class _N_1 : public _N_Base
{
public:
void fun(){A *p = (A*)this; p->fun();}
};

int main(int argc, char *argv[])
{
_N_1 obj;
obj.fun();
return 0;
}

#5


public:

xmlNodePtr GetProp(){ return xmlNodePtr; }

大哥,看清楚了,是public方法,friend 有什么用

#6


其实你全public就可以了。封装不是一定要用语法机制来限制访问,人的自律更重要。

#7


我的意思通过程序的结构来考虑,设计出更加 合理方便的类结构,而不是通过各种诡异的手段来实现各种常理下不可达的目的。

#8


该回复于2011-11-04 17:13:22被版主删除

#9


都私有了,你为啥要访问啊。

#10


改为protected的成员数据。

#11


因为派生类需要的信息在那个基类中啊,所以要放呢,

我之所以问这个问题并不是我不知道如何访问到这个基类中的函数(要访问其实很简单《1》每个类都实现一个接口来调用自己的成员变量,但是这样如果某个类的成员变量有好多属性需要外部访问,那么使用这个成员的类就得提供好多接口来实现外部对这个类成员的访问,《2》类中的成员变量设为公有的,但是这样不就失去类的封装性及数据私有化的作用了吗)

我的意思是尽量减少对类封装性的破坏,这使矛盾的,但是我觉得肯定有一个平衡点,我目前采用的是继承。

#12


1. 正常的解决方法:用正常的办法的话,你可以不改变成员变量的属性,但你必须在各类中增加一个public成员函数,来获得那个私有成员变量。


#include <iostream>
using namespace std;
class A  
{
public:
//xmlNodePtr GetProp(){ return xmlNodePtr; }
void print_some_info() // 用这个函数代替上面那个函数做实验
{
cout << "hello, class A" << endl;
}
};

class B
{
public:
A getMemberA()
{
return m_a; // 严格地,这要求A实现拷贝构造函数
}
private:
A m_a;
};

class C
{
public:
B getMemberB()
{
return m_b; // 严格地,这要求B实现拷贝构造函数
}
private:
B m_b;
};

class N : public C
{
public:
void print_info()
{
getMemberB().getMemberA().print_some_info();
}
};

int main(void)
{
N n;
n.print_info();

return 0;
}


2. 不正常的解决办法:

#include <iostream>
using namespace std;
class A  
{
public:
//xmlNodePtr GetProp(){ return xmlNodePtr; }
void print_some_info() // 用这个函数代替上面那个函数做实验
{
cout << "hello, class A" << endl;
}
};

class B
{
private:
A m_a;
};

class C
{
private:
B m_b;
};

class N : public C
{
public:
};

int main(void)
{
N n;

((A*)((B*)(&((C)n))))->print_some_info();
        // 说明:
        // (C)n:         
        //  1. 将n由N转型为C,用static_cast也可以,那么(通过剪裁)可以得到一个C对象

        // &((C)n)     
        // 2. 取1中所得到对象的地址

        // (B*)(&((C)n))  
        // 3. C对象中的第一个成员变量是B类型的m_b,因此我们可以通这种方式得到m_b的地址

        // (A*)((B*)(&((C)n))) 
        // 4. m_b这个B对象的第一个成员变量是A类型的m_a,因此我们可以通过这种方式得到m_a的地址

        // ((A*)((B*)(&((C)n))))->print_some_info();
        // 5. 用m_a的地址去调用print_some_info()
return 0;
}

用这种不正常的方法,要求对C++对象模型比较了解才行。

#13


该回复于2011-11-07 09:15:06被版主删除

#14


要不就让成员为Protected,要不就提供Protected方法private成员,让子类提供Public接口调用Protected方法。

#15


恩,其实我仔细想了想,无非也就是层层的接口调用或是类继承这两种方法,不正常的方法不可以用,防止以后编译器的变动导致诡异的手段失效