Nested classes (C++ only)

本文探讨了C++中嵌套类的访问规则及成员访问权限问题,通过具体示例解释了私有成员在不同情况下如何被正确访问,以及标准变更如何影响编译器行为。

access rules and nested classes

The following example (adapted from standard, section 11.8.1)

class E
{
int x;
class I
{
void f(E* p, int i)
{
p->x = i; // error
}
};
};

is illegal because nested class I has no special access to enclosing class
E. E::x is private and therefore p->x is an access error.

Yet Comeau C++, gcc 3.2 and Visual C++ 7.1 all compile it. What is going on?
Has the standard changed recently?

john

A:It is a bug in these compilers. HP's aCC compiler gives the expected error.
The other vendors are being milder.
B:Actually I found this

http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#45

the standard is going to change in this regard. I guess gcc, Comeau and VC++
are anticipating the change while aCC is not.

John

Nested classes (C++ only)

A nested class is declared within the scope of another class. The name of a nested class is local to its enclosing class. Unless you use explicit pointers, references, or object names, declarations in a nested class can only use visible constructs, including type names, static members, and enumerators from the enclosing class and global variables.

Member functions of a nested class follow regular access rules and have no special access privileges to members of their enclosing classes. Member functions of the enclosing class have no special access to members of a nested class. The following example demonstrates this:

class A {
int x;

class B { };

class C {

// The compiler cannot allow the following
// declaration because A::B is private:
// B b;

int y;
void f(A* p, int i) {

// The compiler cannot allow the following
// statement because A::x is private:
// p->x = i;

}
};

void g(C* p) {

// The compiler cannot allow the following
// statement because C::y is private:
// int z = p->y;
}
};

int main() { }

The compiler would not allow the declaration of object b because class A::B is private. The compiler would not allow the statement p->x = i because A::x is private. The compiler would not allow the statement int z = p->y because C::y is private.

You can define member functions and static data members of a nested class in namespace scope. For example, in the following code fragment, you can access the static members x and y and member functions f() and g() of the nested class nested by using a qualified type name. Qualified type names allow you to define a typedef to represent a qualified class name. You can then use the typedef with the :: (scope resolution) operator to refer to a nested class or class member, as shown in the following example:

class outside
{
public:
class nested
{
public:
static int x;
static int y;
int f();
int g();
};
};
int outside::nested::x = 5;
int outside::nested::f() { return 0; };

typedef outside::nested outnest; // define a typedef
int outnest::y = 10; // use typedef with ::
int outnest::g() { return 0; };

However, using a typedef to represent a nested class name hides information and may make the code harder to understand.

You cannot use a typedef name in an elaborated type specifier. To illustrate, you cannot use the following declaration in the above example:

  class outnest obj;

A nested class may inherit from private members of its enclosing class. The following example demonstrates this:

class A {
private:
class B { };
B *z;

class C : private B {
private:
B y;
// A::B y2;
C *x;
// A::C *x2;
};
};

The nested class A::C inherits from A::B. The compiler does not allow the declarations A::B y2 and A::C *x2 because both A::B and A::C are private.


9.7 Nested class declarations
1 A class can be defined within another class. A class defined within another is called a nested class. The
name of a nested class is local to its enclosing class. The nested class is in the scope of its enclosing class.
Except by using explicit pointers, references, and object names, declarations in a nested class can use only
type names, static members, and enumerators from the enclosing class. [Example:
int x;
int y;
class enclose {
public:
int x;
static int s;
class inner {
void f(int i)
{
int a = sizeof(x); // error: refers to enclose::x
x = i; // error: assign to enclose::x
s = i; // OK: assign to enclose::s
::x = i; // OK: assign to global x
y = i; // OK: assign to global y
}
void g(enclose* p, int i)
{
p->x = i; // OK: assign to enclose::x
}
};
};
inner* p = 0; // error: inner not in scope
—end example]
2 Member functions and static data members of a nested class can be defined in a namespace scope enclosing
the definition of their class. [Example:

class enclose {
public:
class inner {
static int x;
void f(int i);
};
};
int enclose::inner::x = 1;
void enclose::inner::f(int i) { /* ... */ }
—end example]
3 If class X is defined in a namespace scope, a nested class Y may be declared in class X and later defined in
the definition of class X or be later defined in a namespace scope enclosing the definition of class X.
[Example:
class E {
class I1; // forward declaration of nested class
class I2;
class I1 {}; // definition of nested class
};
class E::I2 {}; // definition of nested class
—end example]
4 Like a member function, a friend function (11.4) defined within a nested class is in the lexical scope of that
class; it obeys the same rules for name binding as a static member function of that class (9.4) and has no
special access rights to members of an enclosing class.

### 定义 Nested Classes(嵌套类),也称为内部类,是在一个类内部定义的类。在 Java 中,可以在一个类的内部定义另一个类,这个被定义的类就成为嵌套类。嵌套类可以有不同的类型,包括静态嵌套类、成员内部类、局部内部类和匿名内部类[^2]。 ### 使用方法 #### 静态嵌套类 静态嵌套类使用 `static` 关键字修饰,它可以直接访问外部类的静态成员,但不能直接访问外部类的非静态成员。创建静态嵌套类对象的格式如下: ```java class Outer { static class StaticNested { void printMessage() { System.out.println("This is a static nested class."); } } } public class Main { public static void main(String[] args) { Outer.StaticNested nested = new Outer.StaticNested(); nested.printMessage(); } } ``` #### 成员内部类 成员内部类是定义在外部类的成员位置,没有 `static` 修饰。成员内部类可以访问外部类的所有成员,包括私有成员。创建成员内部类对象的格式如下: ```java class Outer { class Inner { void printMessage() { System.out.println("This is a member inner class."); } } } public class Main { public static void main(String[] args) { Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); inner.printMessage(); } } ``` #### 局部内部类 局部内部类是定义在方法或代码块中的类,它的作用域仅限于定义它的方法或代码块。 ```java class Outer { void outerMethod() { class LocalInner { void printMessage() { System.out.println("This is a local inner class."); } } LocalInner localInner = new LocalInner(); localInner.printMessage(); } } public class Main { public static void main(String[] args) { Outer outer = new Outer(); outer.outerMethod(); } } ``` #### 匿名内部类 匿名内部类是没有名字的局部内部类,通常用于创建只需要使用一次的类对象。 ```java interface MyInterface { void doSomething(); } public class Main { public static void main(String[] args) { MyInterface myInterface = new MyInterface() { @Override public void doSomething() { System.out.println("This is an anonymous inner class."); } }; myInterface.doSomething(); } } ``` ### 应用场景 - **封装性**:将相关的类组合在一起,提高代码的封装性,隐藏实现细节。例如,一个 `List` 接口的实现类可能会使用嵌套类来实现迭代器。 - **事件处理**:在图形用户界面(GUI)编程中,经常使用匿名内部类来处理事件。例如,在 Java Swing 中,为按钮添加点击事件监听器。 - **代码复用**:局部内部类可以在方法内部复用代码,避免代码重复。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值