马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
目次
嵌套类
嵌套类的界说
嵌套类结构的访问权限
pimpl模式(了解)
嵌套类
嵌套类的界说
起首介绍两个概念:
类作用域是指在类界说内部的范围。在这个作用域内界说的成员(包括变量、函数、范例别名等)可以被该类的全部成员函数访问。类作用域开始于类界说的左花括号,结束于类界说的右花括号。在类作用域内,成员可以相互访问,无论它们在类界说中的声明次序怎样。
类名作用域指的是可以通过类名访问的作用域。这紧张用于访问类的静态成员、嵌套范例。类名必须用于访问静态成员或嵌套范例,除非在类的成员函数内部,由于它们不依赖于类的任何特定对象。以静态成员为例:
- class MyClass
- {
- public:
- void func(){
- _b = 100;//类的成员函数内访问_b
- }
- static int _a;
- int _b;
- };
- //静态成员要定义在类外,因为静态成员是一个类所共有的,如果声明在类中,每创建一个类对象就会生成一个静态数据成员
- int MyClass::_a = 0;
- void test0(){
- //这里静态数据成员为公有所以可以在类外通过类名直接访问
- MyClass::_a = 200;//类外部访问_a
- }
复制代码
在函数和其他类界说的外部界说的类称为全局类,绝大多数的 C++ 类都是全局类。我们在前面界说的全部类都在全局作用域中,全局类具有全局作用域。
与之对应的,一个类A还可以界说在另一类B的界说中,这就是嵌套类结构。A类被称为B类的内部类,B类被称为A类的外部类。
以Point类和Line类为例
- class Line
- {
- public:
- class Point{
- public:
- Point(int x,int y)
- : _ix(x)
- , _iy(y)
- {}
- private:
- int _ix;
- int _iy;
- };
- public:
- Line(int x1, int y1, int x2, int y2)
- : _pt1(x1,y1)
- , _pt2(x2,y2)
- {}
- private:
- Point _pt1;
- Point _pt2;
- };
复制代码
Point类是界说在Line类中的内部类,无法直接创建Point对象,必要在Line类名作用域中才气创建,由于point类在line类中,只能先找到line类在访问point类
- Point pt(1,2);//error
- Line::Point pt2(3,4);//ok
复制代码 Point类是Line类的内部类,并不代表Point类的数据成员会占据Line类对象的内存空间,在存储关系上并不是嵌套的结构。
只有当Line类有Point类范例的对象成员时,Line类对象的内存结构中才会包含Point类对象(成员子对象)。
(1)如果Line类中没有Point类的对象成员,sizeof(Line) = 8;
(2)如果Line类中有两个Point类的对象成员,sizeof(Line) = 24;
思索,如果想要利用输出流运算符输出Line对象,应该怎么实现?(紧张)
最直观的实现方式是界说一个运算符重载函数,但在函数体中必要让输出流运算符处置处罚Point范例对象,以是还必要为Point类准备一个输出流运算符重载函数。
—— 如果Point界说在Line的私有地区
那么还必要将operator<<函数声明为Line的友元函数
下面为测试代码,可自行测试
- #include <iostream>
- using namespace std;
- class Line
- {
- public:
- class Point {
- public:
- Point(int x, int y)
- : _ix(x)
- , _iy(y)
- {}
- friend ostream& operator<<(ostream& os, const Line::Point& rhs);
- private:
- int _ix;
- int _iy;
- };
- public:
- Line(int x1, int y1, int x2, int y2)
- : _pt1(x1, y1)
- , _pt2(x2, y2)
- {}
- ~Line() {
- //cout << "~Line()" << endl;
- }
- friend ostream& operator<<(ostream& os, const Line& rhs);
- friend ostream& operator<<(ostream& os, const Point& rhs);
-
- private:
- Point _pt1;
- Point _pt2;
- };
- //这里会访问line的私有成员point所以在line类中声明为友元,因为又要访问point对象的数据成员,
- //所以又要将这个函数声明为内部类的友元
- ostream& operator<<(ostream& os, const Line::Point& rhs)
- {
- os << "(" << rhs._ix << "," << rhs._iy << ")";
- return os;
- }
- //因为是输出运算符重载,不会对操作数进行修改,倾向于声明为有友元类
- ostream& operator<<(ostream & os, const Line & rhs)
- {
- os << rhs._pt1 << "------->" << rhs._pt2;
- return os;
- }
- void test()
- {
- Line ll(1, 2, 3, 4);
- cout << ll << endl;
- }
- int main()
- {
- test();
- return 0;
- }
复制代码
嵌套类结构的访问权限
外部类对内部类的成员举行访问
内部类对外部类的成员举行访问
内部类相称于是界说在外部类中的外部类的友元类
类A界说在类B中,那么类A访问类B的成员时,就相称于默认的是类B的友元类。

下面为测试代码,可以自行测试
- #include <iostream>
- using namespace std;
- class Line
- {
- public:
- class Point {
- public:
- Point(int x, int y)
- : _ix(x)
- , _iy(y)
- {}
- friend ostream& operator<<(ostream& os, const Line::Point& rhs);
- void print()
- {
- cout << "print" << endl;
- }
- friend class Line;
- void getline(const Line& rhs)
- {
- //在内部类中不需要友元声明,可以直接通过line对象直接访问成员
- rhs._pt1;
- rhs._pt2;
- //通过类名作用域直接访问line的私有静态成员
- Line::_pt3;
- //直接用成员名访问line的私有静态数据成员
- _pt3;
- }
- private:
- int _ix;
- int _iy;
- static int _iz;
- };
- public:
- Line(int x1, int y1, int x2, int y2)
- : _pt1(x1, y1)
- , _pt2(x2, y2)
- {}
- ~Line() {
- //cout << "~Line()" << endl;
- }
- friend ostream& operator<<(ostream& os, const Line& rhs);
- friend ostream& operator<<(ostream& os, const Point& rhs);
- void getpoint()
- {
- //在外部类中通过内部类访问内部类的公有成员
- _pt1.print();//ok
- //外部类属于内部类的类定义之外,这里是在内部类的私有数据成员
- //在外部类中通过内部类对象访问内部类的私有成员
- //_pt1._ix;//需要声明友元
- Point::_iz;//因为为私有,所以需要友元声明
-
- //_ix;不可能实现
- //_iy;同上
- }
- private:
- Point _pt1;
- Point _pt2;
- static double _pt3;
- };
- //要在外部类的外面对内部类的静态成员进行定义
- int Line::Point::_iz = 10;
- double Line::_pt3 = 100;
- //这里会访问line的私有成员point所以在line类中声明为友元,因为又要访问point对象的数据成员,
- //所以又要将这个函数声明为内部类的友元
- ostream& operator<<(ostream& os, const Line::Point& rhs)
- {
- os << "(" << rhs._ix << "," << rhs._iy << ")";
- return os;
- }
- //因为是输出运算符重载,不会对操作数进行修改,倾向于声明为有友元类
- ostream& operator<<(ostream & os, const Line & rhs)
- {
- os << rhs._pt1 << "------->" << rhs._pt2;
- return os;
- }
- void test()
- {
- Line ll(1, 2, 3, 4);
- cout << ll << endl;
- }
- int main()
- {
- test();
- return 0;
- }
复制代码 pimpl模式(了解)
现实项目标需求:盼望Line的实现全部隐藏,在源文件中实现,再将其打包成库文件,交给第三方利用。
(1)头文件只给出接口:
- //Line.hpp
- class Line{
- public:
- Line(int x1, int y1, int x2, int y2);
- ~Line();
- void printLine() const;//打印Line对象的信息
- private:
- class LineImpl;//类的前向声明
- LineImpl * _pimpl;
- };
复制代码
(2)在实现文件中举行详细实现,利用嵌套类的结构(LineImpl是Line的内部类,Point是LineImpl的内部类),Line类对外公布的接口都是利用LineImpl举行详细实现的
在测试文件中创建Line对象(最外层),利用Line对外提供的接口,但是不知道详细的实现
- //LineImpl.cc
- class Line::LineImpl
- {
- class Point{
- public:
- Point(int x,int y)
- : _ix(x)
- , _iy(y)
- {}
- //...
- private:
- int _ix;
- int _iy;
- };
- //...
- };
- //Line.cc
- void test0(){
- Line line(10,20,30,40);
- line.printLine();
- }
复制代码
(3)打包库文件,将库文件和头文件交给第三方
- sudo apt install build-essential
- g++ -c LineImpl.cc
- ar rcs libLine.a LineImpl.o
- 生成libLine.a库文件
- 编译:g++ Line.cc(测试文件) -L(加上库文件地址) -lLine(就是库文件名中的lib缩写为l,不带后缀)
- 此时的编译指令为 g++ Line.cc -L. -lLine
复制代码
内存结构
pimpl模式是一种镌汰代码依赖和编译时间的C++编程本事,其根本头脑是将一个外部可见类的实现细节(一样平常是通过私有的非虚成员)放在一个单独的实现类中,在可见类中通过一个私有指针来间接访问该范例。
长处:
- 实现信息隐藏;
- 只要头文件中的接口稳定,实现文件可以随意修改,修改完毕只必要将新天生的库文件交给第三方即可;
- 可以实现库的平滑升级。
下面为测试代码,可自行测试
- //LineImpl.cc
- #include <iostream>
- #include "Line.hpp"
- using namespace std;
- // 这是一个实现文件,不用包含测试,只需要实现头文件中的函数等内容
- //先对成员类型进行实现
- class Line::LineImpl
- {
- public:
- class Point{
- public:
- Point(int x,int y)
- : _ix(x)
- , _iy(y)
- {}
- ~Point()
- {
- cout << "~Point()" << endl;
- }
- void print()
- {
- cout << "("<<_ix << ","
- << _iy << ")";
- }
- private:
- int _ix;
- int _iy;
- };
- public:
- LineImpl(int x1, int y1, int x2, int y2)
- : _pt1(x1,y1)
- , _pt2(x2,y2)
- {
- cout << "LineImpl(int *4)" << endl;
- }
- ~LineImpl()
- {
- cout << "~LineImpl()" << endl;
- }
- void printline()
- {
- _pt1.print();
- cout << "-----> ";
- _pt2.print();
- cout << endl;
- }
- private:
- Point _pt1;
- Point _pt2;
- };
- Line::Line(int x1, int y1, int x2, int y2)
- :_pimpl(new LineImpl(x1,y1, x2,y2))
- {
- cout << "Line(int * 4)" << endl;
- }
- Line :: ~Line()
- {
- cout << "~Line()" << endl;
- if(_pimpl)
- {
- delete _pimpl;
- _pimpl = nullptr;
- }
- }
- void Line::printLine() const{
- _pimpl->printline();
- }
- // test.cc
- #include "Line.hpp"
- #include <iostream>
- using std::cout;
- using std::endl;
- void test()
- {
- Line ll(1,2,3,4);
- ll.printLine();
- }
- int main()
- {
- test();
- return 0;
- }
- //Line.hpp
- #ifndef _Line_HPP_
- #define _Line_HPP_
- class Line {
- public:
- Line(int x1, int y1, int x2, int y2);
- ~Line();
- //提供给客户使用的功能
- void printLine() const;//打印Line对象的信息
- private:
- class LineImpl;//类的前向声明
- LineImpl* _pimpl;
- };
- #endif
复制代码
|