C++内部类的ISO约定和语法细节

目录

基本定义

嵌套类对外部类的访问权限

sizeof(外部类)

内部类友元函数的权限

内部类函数类外实现和延迟声明

访问限定符对内部类的影响

总结


基本定义

内部类也成为嵌套类,英文名叫做nested classes。接下来我们统称内部类。

核心规则:

  • 内部类是声明在另外一个类内部的类、结构体或者联合体。就相当于在一个类里面又定义了一个类,外面这一层称为外围类,或者叫做外部类,英文名是enclosing class。
  • 内部类的名字仅仅存在于外部类的作用域中,也就是想要用这个名字,就得像std::string一样使用这个类,只不过这里指定的不是命名空间,而是外部类的类域。例如: OuterClass::InnerClass。
  • 因为在外部类的里面,因此这里会涉及到很多类成员访问的原则,后续讲解。

代码示例:

cpp 复制代码
#include <iostream>
#include <string>


std::string str = "全局作用域str";
class Outer {
private:
    std::string str = "Outer的私有str";
public:
    class Inner {
    public:
        std::string str = "Inner的公有str";
        void show_str() {
            std::cout << str << std::endl;
        }
    };
    void show_str() {
        std::cout << str << std::endl;
    }
};

int main() {
    // 创建一个Outer类对象
    Outer outer_class;
    // 创建一个Inner类对象
    Outer::Inner inner_class;

    outer_class.show_str();
    inner_class.show_str();
    return 0;
}

输出:

cpp 复制代码
Outer的私有str
Inner的公有str

如果你想在内部类或者外部类中访问全局变量的str,只需要指定全局域就可以:

cpp 复制代码
std::string str = "全局作用域str";
class Outer {
private:
    std::string str = "Outer的私有str";
public:
    class Inner {
    public:
        std::string str = "Inner的公有str";
        void show_str() {
            std::cout << str << std::endl;
            // 指定全局作用域 -- ::str
            std::cout << ::str << std::endl;
        }
    };
    void show_str() {
        std::cout << str << std::endl;
        std::cout << ::str << std::endl;
    }
};

嵌套类对外部类的访问权限

既然是在类的内部定义的,那么必然会涉及到权限相关的问题。

cpp 复制代码
#include <iostream>
#include <string>


std::string str = "全局作用域str";
class Outer {
private:
    static std::string str_static;
    std::string private_str = "Outer的私有str";
public:
    std::string public_str = "Outer的公有str";
    class Inner {
    public:
        void show_str(Outer* out = nullptr) {
            // 直接访问静态变量
            std::cout << str_static << std::endl;
            // 访问out的private str
            std::cout << out->private_str << std::endl;
            // 访问out的public str
            std::cout << out->public_str << std::endl;
            // 访问全局域的str
            std::cout << ::str << std::endl;
        }
    };
};

std::string Outer::str_static("Outer的static私有str");

int main() {
    Outer outer_obj;
    Outer::Inner inner_obj;
    inner_obj.show_str(&outer_obj);
    return 0;
}

输出:

bash 复制代码
Outer的static私有str
Outer的私有str
Outer的公有str
全局作用域str

从上述代码可以看到,内部类是可以访问外部类定义的public, private和static成员变量的。只不过需要注意的是,访问外部类的非静态成员变量,首先需要一个外部类的对象才可以访问,只有静态的外部类的成员变量才可以直接通过类域在内部类中访问。

访问外部类的成员变量的时候,必须要在内存里面现有一个外部类的对象,你才可以访问其成员变量,因为有地址你才可以访问。你在内部类中访问外部类的成员变量,内部类的成员函数传递的是内部类的this指针给内部类的成员函数,并没有传递外部类的this指针,因此需要显式传递外部类的对象的地址。

sizeof(外部类)

对一个定义类内部类的外部类进行sizeof操作会发生什么?

cpp 复制代码
#include <iostream>
#include <string>

class Outer {
public:
	int x;
	int y;
	class Inner {
	public:
		int a;
		int b;
	};
};

int main() {
	Outer outer_obj;
	std::cout << sizeof(outer_obj) << std::endl;
	return 0;
}

结果输出:8

可以得知,内部类的定义在编译之后运行时是不占用栈空间的,因为在构建外部类对象的时候,并不会生成一个内部类的对象,它只是定义在外部类中,创建外部类对象并不会同时创建一个内部类对象。

内部类友元函数的权限

在内部类中定义的友元函数没有对外部类成员的特殊访问权限,友元仅仅只针对当前类,无法从内部类,延伸到外部类。

下面是错误的定义:

cpp 复制代码
#include <iostream>
#include <string>

class Outer {
private:
	int x = 10;
	int y = 20;
	class Inner {
	public:
		friend void access_outer(Outer* out);
	};
public:

};

void access_outer(Outer* out) {
	std::cout << out->x + out->y << std::endl;
	return;
}


int main() {
	Outer outer_obj;
	access_outer(&outer_obj);
	return 0;
}

这个定义中,虽然access_outer是Inner类的友元函数,它可以访问Inner内的私有成员,但即使如此,它依旧访问不了Outer中的私有成员:

如果想访问,那么需要做出如下修改:

  • 将友元声明挪至外部类中
  • 将外部类的私有成员改为公有(public)

内部类函数类外实现和延迟声明

这个就是一个声明和定义分离,没啥好说的,看代码:

cpp 复制代码
#include <iostream>

class Enclose {
public:
    class Inner {
        static int static_x; // 静态成员声明
        void f(int i);       // 成员函数声明
    };
};

// 1. 嵌套类静态成员的类外定义
int Enclose::Inner::static_x = 100;

// 2. 嵌套类成员函数的类外定义
void Enclose::Inner::f(int i) {
    std::cout << "Enclose::Inner::f called with i = " << i << std::endl;
}

注意在外部类外定义内部类的函数的时候,需要先加外部类域,然后加内部类域,形如:

Outer_class::Inner_Class::function(参数列表) { ... } ;

所谓延迟声明,也就是可以先声明,然后再定义:

cpp 复制代码
class Enclose {
    class Nested1; // 前向声明 Nested1
    class Nested2; // 前向声明 Nested2

    // 1. 在外部类内部定义 Nested1
    class Nested1 {
    public:
        void show() { cout << "Nested1 defined inside Enclose" << endl; }
    };
};

// 2. 在外部类外部定义 Nested2
class Enclose::Nested2 {
public:
    void show() { cout << "Nested2 defined outside Enclose" << endl; }
};

在enclose类中,先声明了Nested1和Nested2,然后在外部类内定义了Nested1,在外部类外定义了Nested2(外部定义注意加外部类域)。

访问限定符对内部类的影响

作为外部类的内部类定义,其自身可见性受到private等关键字的影响,例如:

下面是一个错误的示范:

cpp 复制代码
#include <iostream>
using namespace std;
class Outer {
private:
    class Inner { // 私有嵌套类
        void g() { cout << "Inner::g() called" << endl; }
    };

public:
    static Inner f() { return Inner{}; }
};

int main() {
    Outer::Inner inner_obj;
}

无法访问Outer中的Inner:

总结

规则维度 核心要点
作用域与名字查找 嵌套类名字在外部类作用域内,查找顺序:嵌套类 → 外部类 → 全局
访问外部类非静态成员 必须通过外部类对象 / 指针 / 引用
访问外部类静态成员 可直接访问
嵌套类中友元函数 无外部类成员特殊访问权
类外定义 需用 外部类::嵌套类::成员 语法
前向声明 可先声明,后在外部类内 / 外定义
可见性(访问限定符) private 嵌套类外部无法命名,但可通过接口操作对象
相关推荐
wjs20242 小时前
C# 常量
开发语言
Ma_Hong_Kai2 小时前
CMFCRibbonBar
开发语言·visualstudio·mfc
jaysee-sjc2 小时前
【练习十二】Java实现年会红包雨小游戏
java·开发语言·算法·游戏·intellij-idea
LONGZETECH2 小时前
新能源汽车充电设备装配与调试仿真教学软件 技术解析与教学落地
开发语言·系统架构·汽车·汽车教学软件·智能网联汽车软件
User_芊芊君子2 小时前
2026最新Python+AI入门指南:从零基础到实战落地,避开90%新手坑
开发语言·人工智能·python
艾莉丝努力练剑2 小时前
【脉脉】AI创作者崛起:掌握核心工具,在AMA互动中共同成长
运维·服务器·c++·人工智能·安全·企业·脉脉
篮l球场2 小时前
Trie(字典树/前缀树)
开发语言·c#
似水明俊德2 小时前
15-C#
android·开发语言·c#
码界奇点2 小时前
基于ASP.NET Core的内容管理系统设计与实现
c++·后端·车载系统·毕业设计·asp.net·源代码管理