简介:
C++中,允许在一个类中定义另外一个类,在类中定义的类称为嵌套类(或内部类),定义嵌套类的类被称为外部类。定义嵌套类的目的在于隐藏类名,减少全局的标识符,从而限制用户能否使用该类建立对象。这样可以提高类的抽象能力,并且强调了两个类(外部类和嵌套类)之间的主从关系。
嵌套类的用法注意事项:
1)作用域:嵌套类被隐藏在外部类之中,该类名只能在外围类中使用。如果在外部类的作用域内使用该类名时(也就是外部类的外部),需要加名字限定,形如“外部类类名::内部类类名::内部类的成员函数名”;
2)访问权限:嵌套类名与它的外部类的对象成员名具有相同的访问权限规则。不能访问嵌套类的对象中的私有成员函数,也不能对外部类的私有部分中的嵌套类建立对象;
3)声明与定义:C++嵌套类必须声明在类的内部,但是可以定义在类的内部或者外部;在外部类之外定义一个嵌套类时,必须以外层类的名字限定嵌套类的名字;
4)嵌套类中说明的成员不是外围类中对象的成员,反之亦然。嵌套类的成员函数对外围类的成员没有访问权,反之亦然。国此,在分析嵌套类与外围类的成员访问关系时,往往把嵌套类看作非嵌套类来处理;
5)嵌套类是类封装演化出来的又一种类间关系,即其中组合或者聚集的成员不是产生于其他类,而是产生于嵌套类;
6)C++中,允许一个类继承另一个类的内部类,即内部类做为父类, 这时,必须用 “外部类类名::内部类类名”来访问内部类。
程序实例:
例1: 定义一个简单的内部类:
分别“在内部类声明时定义内部类的成员函数”,和“在外部类之外进行内部类成员函数的实现”。
#include <iostream>
using namespace std;
class A {
public:
int a;
void fun1() {cout<<"A::fun1"<<endl;}
class B{
public:
int b;
void fun2() {cout<<"B::fun2"<<endl;}
void fun3();
};
};
//在外部类之外进行内部类的定义(实现),必须指明外部类,即外部类类名::内部类类名::内部类的成员函数名
void A::B::fun3() {
cout<<"B::fun3"<<endl;
}
void test_fun() {
A a;
//B b; //error: unknown type name 'B'; did you mean 'A::B'?
A::B b; //正确
//b.fun1(); //error: no member named 'fun1' in 'A::B'; did you mean 'fun2'?
b.fun2(); // 输出: B::fun2
b.fun3(); // 输出: B::fun3
}
int main()
{
test_fun();
return 0;
}
/*
编译环境:mac os下用g++编译:
*/
具体代码解释,直接参考代码注释。
例子2: 在外部继承另一个类的内部类:
C++中,允许一个类继承另一个类的内部类,即内部类做为父类, 这时,必须用 “外部类类名::内部类类名”来访问内部类。
对于例1中的代码,继续增加一个类D,继承自B,看如下的代码,
//error
class D: public B { // error: unknown class name 'B'; did you mean 'A::B'?
};
根据错误信息提示,很明显,编译器并不知道内部类B的存在。
正确的代码如下:
//success
class D: public A::B { // error: unknown class name 'B'; did you mean 'A::B'?
};
void test_fun() {
D d;
//d.fun1(); //error: no member named 'fun1' in 'D'。类A与类D没有继承关系,类D的实例d不能访问A的成员函数和数据成员。
d.fun2(); //输出:B::fun2。 继承自于父类B的fun2成员函数
d.fun3(); //输出:B::fun3。 继承自于父类B的fun3成员函数
}
分析:
1)D继承自A的内部类B;
2)D的对象d无法访问A的成员函数,因为二者不具有继承关系;
3)D的对象d可以访问B的成员函数,尽管B是A的内部类,因为D继承自B。
例3: 如何通过内部类访问外部类的数据。
看下面的代码,
#include <iostream>
#define method_setOutMemer(classA, classB) \
classA* pA = ((classA*)((char*)(this) - \
offsetof(classA, m_x##classB))); \
using namespace std;
class A
{
private:
int a;
public:
//外部类的构造函数
A(){a=0;}
//输出函数
void printA(){cout<<"A::printA, a="<<a<<endl;}
//内部类
class B
{
private:
int b;
public:
//内部类的构造函数
B(){b=1;}
//输出函数
void printB(){cout<<"B::printB, b="<<b<<endl;}
//访问外部类
void setA()
{
method_setOutMemer(A,B);
pA->a=100;
}
} m_xB;
public:
};
int main()
{
A a;
a.printA(); //输出:A::printA, a=0
a.m_xB.setA(); //通过内部类的成员函数修改外部类的值
a.printA(); //输出:A::printA, a=100
return 0;
}
说明:
offsetof(A, m_x##B)获得的是m_xB在该内存块中与该内存块起始地址(这正是外部类实例的地址)的距离(偏移),即内部类this-外部类this的差值(以字节为单位)这样,用内部类this减去其自身的偏移,便可得到外部类实例a的指针pA。有了这个指针,就可以访问其对应的数据了。
本文详细介绍了C++中嵌套类的概念、作用域、访问权限等知识点,并通过多个实例展示了如何定义和使用嵌套类,包括如何通过内部类访问外部类的数据。
2767

被折叠的 条评论
为什么被折叠?



