14.嵌套类

14.面向对象-封装-嵌套类


14.1 知识点

嵌套类是什么

  • 嵌套类是指声明定义在一个类内部的类
  • 就像俄罗斯套娃一样,在类当中还有类的声明和定义

嵌套类的声明和定义

  • 嵌套类的声明:

    • 直接在某一个类中(类语句块中)
    • 按照类声明语法进行声明
  • 嵌套类的定义:

    • 在宿主类中直接定义或在其 .cpp 中进行定义
    • 定义时需要使用 类名::类名::成员名 这种形式明确属于哪一个类
  • 注意:

    • 嵌套类和外部类本质上是彼此独立的,嵌套类并不像外部类的成员那样紧密
    • 嵌套类和普通类使用上唯一的区别就是需要使用 类名::类名 这种形式表明它是嵌套在一个类之中的
#pragma once
class Outer
{
public:
    int i = 10;

    //private:
    //如果嵌套类是私有的就不能在外部使用了
    class Inner
    {
    private:
        int i = 10;
    public:
        float f = 4.5f;
        void test();

        //允许无限嵌套 
        class OuterInnerInner
        {
        public:
            class OuterInnerInner2
            {
            public:
                class OuterInnerInner3
                {

                };
            };
        };

    protected:
        double d = 5.5;
    };

    //可以有多个嵌套类
    class Inner2
    {

    };

    //Outer类有个Inner类的成员
    Inner inner;
};
#include "Outer.h"

// 我们在定义嵌套类中的成员时,需要明确它被谁包裹着
void Outer::Inner::test()
{

}

受到访问修饰符影响

  • 嵌套类受到访问修饰符影响:

    • public:外部可以用,通过 类名::类名 可以在外部使用嵌套类内容
    • private:只能在外部类内部使用
    • protected:只能在外部类内部和子类中使用
  • public 的嵌套类可以在外部直接声明对象来使用

  • private 和 protected 的嵌套类只能在 Outer 内部或其子类中使用

// Inner 如果是 public 的,可以在外部声明对象
Outer::Inner inner;

无限嵌套

  • 嵌套类中可以再嵌套,理论上可以无限嵌套
  • 使用时只需要通过 类名::类名::类名 往下嵌套使用即可
Outer::Inner::OuterInnerInner::OuterInnerInner2::OuterInnerInner3 q;

作用

  • 封装:将与外部类强相关但不需要对外暴露的类隐藏在内部
  • 辅助类:像外部类的“工具助手”
  • 表达强依赖:表明“这个类仅用于这个类内部”的逻辑
  • 总的来说,嵌套类一般和外部类都有密不可分的关系,如果没有这样的需求,不用强行使用
  • 在日常开发中使用较少,根据需求选择使用即可

14.2 知识点代码

Outer.h

#pragma once
class Outer
{
public:
    int i = 10;

    //private:
    //如果嵌套类是私有的就不能在外部使用了
    class Inner
    {
    private:
        int i = 10;
    public:
        float f = 4.5f;
        void test();

        //允许无限嵌套 
        class OuterInnerInner
        {
        public:
            class OuterInnerInner2
            {
            public:
                class OuterInnerInner3
                {

                };
            };
        };

    protected:
        double d = 5.5;
    };

    //可以有多个嵌套类
    class Inner2
    {

    };

    //Outer类有个Inner类的成员
    Inner inner;
};

Outer.cpp

#include "Outer.h"

//我们在定义嵌套类中的成员时 需要明确它被谁包裹着
void Outer::Inner::test()
{

}

Lesson14_面向对象_封装_嵌套类.cpp

#include <iostream>
#include "Outer.h"
int main()
{
    #pragma region 知识点一 嵌套类是什么
    //嵌套类是指声明定义在一个类内部的类
    //就像俄罗斯套娃一样,在类当中还有类的声明和定义
    #pragma endregion

    #pragma region 知识点二 嵌套类的声明和定义
    //嵌套类的声明:
    //直接在某一个类中(类语句块中)
    //按照类声明语法进行声明
    //嵌套类的定义:
    //在宿主类中直接定义或在其cpp中进行定义
    //定义时需要使用  类名::类名::成员名 这种形式明确属于哪一个类

    //注意:
    //嵌套类和外部类本质上是彼此独立的,嵌套类并不像外部类的成员那样紧密
    //嵌套类和普通类使用上唯一的区别就是需要使用 类名::类名这种形式表明它是嵌套在一个类之中的
    #pragma endregion

    #pragma region 知识点三 受到访问修饰符影响
    //嵌套类收到访问修饰符影响
    //public:外部可以用,通过类名::类名可以在外部使用嵌套类内容
    //private:只能内部用
    //protected:只能内部和子类用

    //public的就可以在外部直接声明对象来使用
    //如果是私有和保护 只能在Outer内部使用 或子类使用

    // Inner如果是pulic的 可以在外部声明Inner对象
    Outer::Inner inner;
    #pragma endregion

    #pragma region 知识点四 无限嵌套
    //嵌套类中可以再嵌套,理论上来说可以无限嵌套
    //在使用时只需要通过 类名::类名::类名 往下嵌套使用即可
    Outer::Inner::OuterInnerInner::OuterInnerInner2::OuterInnerInner3 q;
    #pragma endregion

    #pragma region 知识点五 作用
    //1.封装
    //	将与外部类强相关但不需要对外暴露的类隐藏在内部
    //2.辅助类
    //	像外部类的“工具助手”
    //3.表达强依赖
    //	表明“这个类仅用于这个类内部”逻辑
    //等等
    //总的来说,嵌套类一般和外部类都有密不可分的关系,如果没有这样的需求,不用强行使用
    //它在日常开发时,使用较少,根据需求选择使用即可
    #pragma endregion
}

14.3 练习题

嵌套类是否可以和外部的某个类重名?为什么?

可以重名。C++ 对嵌套类和外部类没有强制的命名限制,它们是完全独立的类型,互不影响。外部类通过 类名::嵌套类名 来引用,而在外部作用域可以直接用 嵌套类名。唯一要注意的是,嵌套类的名字只能和非其宿主(enclosing)类重名。

#pragma once
#include <iostream>
using namespace std;

class Inner
{
public:
    void test()
    {
        cout << "Inner" << endl;
    }
};
#pragma once
#include "Inner.h"
#include <iostream>
using namespace std;

class Outer
{
protected:
    int testI = 100;

public:
    // 这是与外部同名的嵌套类 Inner
    class Inner
    {
    private:
        int testI = 99;
    public:
        void test()
        {
            cout << "Outer::Inner" << endl;
        }
        void SayHello();

        // 嵌套类可以直接访问其宿主类的保护或私有成员
        void PrintAInfo(Outer& o)
        {
            cout << o.testI << endl;
        }
    };

    Inner i;      // 默认引用的是 Outer::Inner
    ::Inner i2;   // ::Inner 表示全局作用域下的 Inner

    // 外部类无法访问嵌套类的私有或保护成员
    void PrintInfo(Inner& i)
    {
        // cout << i.testI << endl; // 编译错误
    }
};
#include "Inner.h"
#include "Outer.h"
#include <iostream>
using namespace std;

void Outer::Inner::SayHello()
{
    cout << "你好呀" << endl;
}
Inner i;            // 全局作用域的 Inner
Outer::Inner i2;    // Outer::Inner

Outer o;
o.i.test();   // 输出:Outer::Inner
o.i2.test();  // 输出:Inner

嵌套类对象的创建与调用

给定以下嵌套类定义:

class Outer {
public:
    class Inner {
    public:
        void SayHello();
    };

    
    //不加 那么默认就是我们内部的这个嵌套类 就是局部去查找的感觉
    Inner i;
};

可以这样创建并调用 SayHello()

Outer o2;
o2.i.SayHello();    // 如果 Outer 中有成员 i

Outer::Inner i3;    
i3.SayHello();      // 在外部直接实例化并调用

嵌套类访问宿主类私有成员的问题

class A {
private:
    int x = 100;

public:
    class B {
    public:
        void PrintX(A& a) {
            std::cout << a.x << std::endl;
        }
    };
};

这段代码没有问题。C++ 中嵌套类可以访问其宿主类的私有成员,因为它们处于同一个作用域:

A a;
A::B b;
b.PrintX(a);  // 输出 100

14.4 练习题代码

Inner.h

#pragma once
#include <iostream>
using namespace std;
class Inner
{
public:
    void test()
    {
        cout << "Inner" << endl;
    }
};

Outer.h

#pragma once
#include "Inner.h"
#include <iostream>
using namespace std;
class Outer
{
//private:
protected:
    int testI = 100;

public:
    class Inner
    {
    private:
        int testI = 99;
    public:
        void test()
        {
            cout << "Outer::Inner" << endl;
        }
        void SayHello();

        //C++中嵌套类 可以直接访问外部宿主类的私有或保护成员,因为他们在同一个作用域当中
        void PrintAInfo(Outer& o)
        {
            cout << o.testI << endl;
        }
    };

    //不加 那么默认就是我们内部的这个嵌套类 就是局部去查找的感觉
    Inner i;
    //::代表全局作用域 这是使用外部的Inner类
    ::Inner i2;

    //外部的类想要访问 嵌套类中的私有或保护是无法访问的
    void PrintInfo(Inner& i)
    {
        //cout << i.testI << endl;
    }
};

Outer.cpp

#include "Outer.h"
#include <iostream>
using namespace std;
void Outer::Inner::SayHello()
{
    cout << "你好呀" << endl;
}

Lesson14_练习题.cpp

#include <iostream>
#include "Outer.h"
#include "Inner.h"
int main()
{
    #pragma region 练习题一
    //嵌套类是否可以和外部的某个类重名?为什么?
    // 
    // 
    //可以重名
    //嵌套类和外部类之间C++并没有强制命名限制
    //他们都是独立的类型,不会相互影响
    //类名::类名
    //类名
    //需要注意:只能和非宿主类重名


    Inner i;
    Outer::Inner i2;

    Outer o;
    o.i.test();//Outer::Inner
    o.i2.test();//Inner
    #pragma endregion

    #pragma region 练习题二
    /*class Outer {
    public:
        class Inner {
        public:
            void SayHello();
        };
    };
    请写出以上嵌套类的对象创建方式,并调用 SayHello() 方法*/


    Outer o2;
    o2.i.SayHello();//你好呀

    //在外部实例化一个嵌套类对象 然后去调用方法
    Outer::Inner i3;
    i3.SayHello();//你好呀

    #pragma endregion

    #pragma region 练习题三
    /*class A {
    private:
        int x = 100;

    public:
        class B {
        public:
            void PrintX(A& a) {
                std::cout << a.x << std::endl;
            }
        };
    };
    以上代码,是否存在问题,应该如何修改?*/
    //这的代码 没有问题 不会报错
    //争议点:嵌套类能不能使用宿主类的私有内容,答案是可以用
    //		 C++中嵌套类 可以直接访问外部宿主类的私有成员,因为他们在同一个作用域当中

    i3.PrintAInfo(o);//100
    #pragma endregion
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏