C++-类和对象

C++-类和对象_第1张图片


目录

一.C语言和C++的区别

二.类的引入

三.类的定义 

        1.类的定义

        2.类的成员方法的两种定义方式:

        3.类的成员变量的定义

四.类的访问限定符及封装

        1.访问限定符

五.面向对象的三大特征

        1.面向对象的三大特征分别是什么

        2.封装

六.类的作用域

七.创建类对象

        1.类对象的实例化

        2.类的大小

        3.匿名对象

八.this指针 

        1.什么是this指针

        2.关于this指针的两个问题。

九.C++类中的默认成员函数

        1.类的6个默认成员函数

        2.构造函数 (完成创建对象时的初始化工作) 是特殊的成员函数 构造函数可以私有化

                a.特性:

                b.类的构造函数的调用

3.析构函数(完成对象销毁时的清理工作) 先定义的后析构,后定义的先析构

        a.特征:

       b.不用显示调用析构函数的情况:

        c.类对象的析构问题

4.拷贝构造函数(特殊的构造函数)是构造函数的重载。

        a.特征:

5.运算符的重载

        什么是运算符的重载

        赋值运算符的重载

                a. 赋值运算符重载格式

                b. 赋值运算符只能重载成类的成员函数不能重载成全局函数

                c. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。

                        注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

        前置++和后置++运算符的重载

                a.前置++:

                b.后置++:

        流定向运算符的重载

6.取地址及const取地址操作符重载

十.const成员

十一.初始化列表

        1.什么是初始化列表

        2.为什么有了构造函数还需要初始化列表:

        【注意】

十二.explicit关键字

十三.Static成员

        1.概念

        2.特性

十四.友元

        1.什么是友元

        2.友元函数

        3.友元类

十五.内部类

        1.概念:

        2.特性:


一.C语言和C++的区别

C++-类和对象_第2张图片

        C语言是 面向过程 的, 关注 的是 过程 ,分析出求解问题的步骤,通过函数调用逐步解决问题。

C++-类和对象_第3张图片         C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

C++-类和对象_第4张图片

C++-类和对象_第5张图片

二.类的引入

        C语言结构体中只能定义变量,在 C++ 中,结构体内不仅可以定义变量,也可以定义函数。
在定义类的时候C++更喜欢使用class代替struct
C++-类和对象_第6张图片

三.类的定义 

        1.类的定义
class className
{
 // 类体:由成员函数和成员变量组成
 
}; // 一定要注意后面的分
        class为 定义类的 关键字, ClassName 为类的名字, {} 中为类的主体,注意 类定义结束时后面 分号不能省
        类体中内容称为类的成员: 类中的 变量 称为 类的属性 成员变量 ; 类中的 函数 称为 类的方法 或者 成员函数
        2.类的成员方法的两种定义方式:
                a. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义 ,编译器可能会将其当成 内联函数 处理。

C++-类和对象_第7张图片

·
               b. 类声明放在.h 文件中,成员函数定义放在 .cpp 文件中,注意: 成员函数名前需要加类名 ::

C++-类和对象_第8张图片

        3.类的成员变量的定义
                成员变量命名规则的建议:
// 我们看看这个函数,是不是很僵硬?classDate
{
public:
void Init(int year)
 {
 // 这里的year到底是成员变量,还是函数形参?
 year = year;
 }
private:
 int year;
};
// 所以一般都建议这样
class Date
{
public:
 void Init(int year)
 {
 _year = year;
 }
private:
 int _year;
};
// 或者这样
class Date
{
public:
 void Init(int year)
 {
 mYear = year;
 }
private:
 int mYear;
};
// 其他方式也可以的,主要看公司要求。一般都是加个前缀或者后缀标识区分就行。

.类的访问限定符及封装

        1.访问限定符

                C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用

C++-类和对象_第9张图片
        【访问限定符说明】
                1. public修饰的成员在类外可以直接被访问。
                2. protected和private 修饰的成员在类外不能直接被访问 ( 此处 protected private 是类似的 )。
                3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。
                4. 如果后面没有访问限定符,作用域就到 } 即类结束。
                5. class的默认访问权限为private struct public( 因为 struct 要兼容 C)。
        注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
        在C++的类中定义的函数默认为inline的,所以当想定义内联函数时,直接在类中定义就可以。
        问题:C++ struct class 的区别是什么?
                解答:C++需要兼容 C 语言,所以 C++ struct 可以当成结构体使用。另外 C++ struct 还可以用来定义类。和class定义类是一样的,区别是 struct 定义的类默认访问权限是 public class 定义的类默认访问权限是private。注意:在继承和模板参数列表位置, struct class 也有区别。

五.面向对象的三大特征

        1.面向对象的三大特征分别是什么
                面向对象的三大特性:封装、继承、多态
        2.封装
        在类和对象阶段,主要是研究类的封装特性,那什么是封装呢?
        封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
        封装本质上是一种管理,让用户更方便使用类。比如:对于电脑这样一个复杂的设备,提供给用户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的 等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计算机厂商在出厂时, 在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计 算机进行交互即可
        在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内 部实现细节,控制哪些方法可以在类外部直接被使用
        只有局部域和全局域会影响生命周期,类域和命名空间域不会影响生命生命周期。

六.类的作用域

         类定义了一个新的作用域,类的所有成员都在类的作用域中在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
class Person
{
public:
 void PrintPersonInfo();
private:
 char _name[20];
 char _gender[3];
 int _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
 cout << _name << " "<< _gender << " " << _age << endl;
}

七.创建类对象

        1.类对象的实例化
                用类类型创建对象的过程,称为类的实例化
                1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个类,来描述具体学生信息。
                  类就像谜语一样,对谜底来进行描述,谜底就是谜语的一个实例。
                  谜语:"年纪不大,胡子一把,主人来了,就喊妈妈" 谜底:山羊
                2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量。
                3. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什 么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间。
        2.类的大小
                和结构体计算大小一样,但是有一点只算成员变量,不计算静态成员变量和静态成员函数和普通成员函数,因为这三者是保存在一个公告存储区域中每一个实例化的对象都可以访问这个空间。
        如果定义的类中只有成员函数或者类中什么都没有那么类的大小是多少呢?
C++-类和对象_第10张图片
        这一个字节是为了占位,表示类对象存在但是不存储任何数据。
        3.匿名对象
        
                A aa(1);    有名对象         生命周期是整个局部作用域
                A(1);      匿名对象         生命周期是当前行,即用即销毁
                匿名对象也可以调用类的成员。
                匿名对象具有常性,const A & aa1 = A(1);此时不会构成也引用,引用延长了该匿名对象的生命周期。
                
                函数的参数是const类型的和非const类型的是可以构成重载的。

八.this指针 

        1.什么是this指针
class Date
{ 
public:
 void Init(int year, int month, int day)
 {
 _year = year;
 _month = month;
 _day = day;
 }
 void Print()
 {
 cout <<_year<< "-" <<_month << "-"<< _day <

                对于上面的代码的d1和d2两个对象在访问成员方法时,既然成员方法都在一个共享空间中,那么为什么两个对象的输出结果不同呢?

                原因就是有 this指针的存在。

                this指针是非静态成员函数默认定义的一个行参 Date&const this; 因为是const类型所以在函数中不可以改变this指针变量的内容。既然是一个形参那么出函数作用时就会销毁。this指针不可以在函数的形参和实参显示传递。

        2.关于this指针的两个问题。

                a.this指针是存放在栈空间的。

                b.this可以为空吗?

                        可以为空

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
 void Print()
 {
 cout << "Print()" << endl;
 }
private:
 int _a;
};
int main()
{
 A* p = nullptr;
 p->Print();
 return 0;
}
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{ 
public:
 void PrintA() 
 {
 cout<<_a<PrintA();
 return 0;
}

       C++-类和对象_第11张图片 

九.C++类中的默认成员函数

        1.类的6个默认成员函数
        如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
        默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。
         C++-类和对象_第12张图片
        2.构造函数 (完成创建对象时的初始化工作) 是特殊的成员函数 构造函数可以私有化
                注意在实例化类对象的时候编译器会去自动调用相应类的构造函数完成对这个类对象的初始化,但是对象的空间是由系统分配的。
                a.特性:
                        1.函数名和类名相同。
                        2.无返回值。
                        3.对象实例化时编译器自动调用对应的构造函数。
                        4.构造函数可以重载。(为了实现不同方式的对象初始化)
                        5.如果没有显式定义构造函数,那么编译器会自动生成一个(默认生成的构造函数内置类型不做处理,自定义类型会去调用它自己的默认构造函数)。
                        6.对于默认生成的构造函数是否会对内置类型处理,不同的编译器会有不同的结果,但是一般记忆为不做处理。
                         C++11中有补丁,声明时可以给缺省值,如果没有传参数那么,或去调用缺省值。
          
                 默认构造函数:无参的构造函数,全缺省的构造函数,编译器自己生成。
                b.类的构造函数的调用
#include 

using namespace std;

class Date
{
public:
	Date(int year = 2023,int month = 12, int day = 31)
	{
		_year  = year ;
		_month = month;
		_day = day    ;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main(void)
{
	Date d1;
	Date d2(2023, 12, 3);
	Date d3();
	return 0;
}
                不可以像d3这样实例化,因为会导致编译器无法识别是函数的声明还是类对象的创建。
        结论:
                1.一般情况下构造函数都要自己写。
                2.可以使用默认生成的构造函数的情况:
                        内置类型成员都有缺省值,且初始化符合我们的要求。
                        全是自定义类型,且这些类型都有自己的默认构造函数。
3.析构函数(完成对象销毁时的清理工作) 先定义的后析构,后定义的先析构
        注意定义好的类对象在出自己的作用域的时候,会归还的对象空间的使用权,此时编译器会去先调用该类对象的析构函数,析构函数是完成对象空间在释放前的清理工作。销毁的行为是系统做的。
        a.特征:
                1.析构函数名是~类名。
                2.无参数,无返回值(不可以重载)。
                3.一个类只能有一个析构函数,若未显示定义,则编译器会默认自动生成一个
                        默认生成的析构函数:内置类型不做处理,自定义类型会去调用它自己的析构函数。
                4.对象生命周期结束时,C++编译器会自动调用析构函数。
       b.不用显示调用析构函数的情况:
                一般情况下,有动态申请资源,需要显示定义析构函数,没有则无,需要释放资源的成员函数都是自定义类型。
        
        c.类对象的析构问题
                在同一作用域下的类对象先构造的后析构: C++-类和对象_第13张图片
   
C++-类和对象_第14张图片
C++-类和对象_第15张图片
4.拷贝构造函数(特殊的构造函数)是构造函数的重载。
        
        a.特征:
                1.拷贝构造函数是构造函数的重载。
                2.拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器会直接报错,因为会无限递归下去。
C++-类和对象_第16张图片
C++-类和对象_第17张图片
                3.如果没有显式定义,编译器会默认生成一个,默认生成的拷贝构造函数是浅拷贝。
                        默认生成的拷贝构造函数:内置类型不做处理,自定义类型回去调用它直接的拷贝构造。
                
C++-类和对象_第18张图片
5.运算符的重载
        什么是运算符的重载
        自定义类型的运算符重载本质是调用函数
C++-类和对象_第19张图片
C++-类和对象_第20张图片
        两个运算符重载的函数又互相构成函数重载。
        赋值运算符的重载
                a. 赋值运算符重载格式
                        参数类型:const T&,传递引用可以提高传参效率。
                        返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值。
                        检测是否自己给自己赋值。
                        返回*this :要复合连续赋值的含义。
C++-类和对象_第21张图片
                b. 赋值运算符只能重载成类的成员函数不能重载成全局函数
        
                原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的 赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的 成员函数。
                c. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝
                        注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。
                既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?
C++-类和对象_第22张图片
        前置++和后置++运算符的重载
                a.前置++:
C++-类和对象_第23张图片
                b.后置++:
C++-类和对象_第24张图片
C++-类和对象_第25张图片
                这个int是为了构成函数的重载。
        
        流定向运算符的重载

                先看下面的代码:

#include 

using namespace std;

class Date
{
public:
	Date(int year = 2023,int month = 12, int day = 31)
	{
		_year  = year ;
		_month = month;
		_day = day    ;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main(void)
{
	Date d1;
	Date d2(2023, 12, 3);
	
	cout << d2;
	return 0;
}
         我们在运行上面的代码时,发现cout并不可以自动识别d2的类型,是因为在库中并没有对自定义类型的流插入运算进行重载,所以此时在使用时cout并不知道该如何打印它。
        
        此时就由两种解决问题的办法:
                
                a.改写的库中的代码,显然是不可能的,但是就算可以,我们有那么多的自定义类型,得改写库代码到什么时候啊。
                
                b.定义成全局函数,但是此时此时还有一个问题,我们没法调用d1中的私有成员啊。
                        可以在类中定义Get方法。
                        使用友元。
#include 

using namespace std;

class Date
{
	friend ostream& operator<< (ostream& cout, const Date& d);

public:
	Date(int year = 2023,int month = 12, int day = 31)
	{
		_year  = year ;
		_month = month;
		_day = day    ;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main(void)
{
	Date d1;
	Date d2(2023, 12, 3);
	
	cout << d1;
	return 0;
}

ostream& operator<< (ostream& cout, const Date& d)
{
	cout << d._year << " " << d._month << " " << d._day << endl;

	return cout;
}

        此时一定要使用ostream&因为ostream类有防止开拷贝的操作。

6.取地址及const取地址操作符重载
         这两个默认成员函数一般不用重新定义 ,编译器默认会生成。
class Date
{ 
public :
 Date* operator&()
 {
 return this ;
 }
 
 const Date* operator&()const
 {
 return this ;
 }
private :
 int _year ; // 年
 int _month ; // 月
 int _day ; // 日
};
        这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容

十.const成员

        将const 修饰的 成员函数 称之为 const 成员函数 const 修饰类成员函数,实际修饰该成员函数 隐含的 this 指针 ,表明在该成员函数中 不能对类的任何成员进行修改。
C++-类和对象_第26张图片
        const类对象最好调用const类方法。

十一.初始化列表

        1.什么是初始化列表
                初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
C++-类和对象_第27张图片
        2.为什么有了构造函数还需要初始化列表:
C++-类和对象_第28张图片
                虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为 初始化只能初始化一次,而构造函数体 内可以多次赋值
        【注意】
                1. 每个成员变量在初始化列表中只能出现一次 ( 初始化只能初始化一次 )
                2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
                        引用成员变量
                        const成员变量
                        自定义类型成员(且该类没有默认构造函数时)
                3.尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。内置类型也会使用初始化列表进行初始化,但是值不确定。
                一般情况下都是初始化列表和构造函数函数体一起使用,虽然初始化列表完成了构造函数的90%的工作,但是还有一些工作是初始化列表完成不了的,所以不能说初始化列表可以完全代替构造函数的函数体。
                4. 成员变量在类中 声明次序 就是其在初始化列表中的 初始化顺序 ,与其在初始化列表中的先后次序无关

十二.explicit关键字

         构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用.
C++-类和对象_第29张图片
        
        上述代码可读性不是很好,用explicit修饰构造函数,将会禁止构造函数的隐式转换

十三.Static成员

        1.概念
                 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰成员函数,称之为静态成员函数静态成员变量一定要在类外进行初始化。
     面试题:实现一个类,计算程序中创建出了多少个类对象。
class A
{
public:
 A() { ++_scount; }
 A(const A& t) { ++_scount; }
 ~A() { --_scount; }
 static int GetACount() { return _scount; }
private:
 static int _scount;
};
int A::_scount = 0;
void TestA()
{
 cout << A::GetACount() << endl;
 A a1, a2;
 A a3(a1);
 cout << A::GetACount() << endl;
}
   
        2.特性
                1. 静态成员所有类对象所共享,不属于某个具体的对象,存放在静态区。
                2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明。
                3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问。
                4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员。
                5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制。
        【问题】
                1. 静态成员函数可以调用非静态成员函数吗?
        
                        不可以因为静态成员函数中没有this指针。
                2. 非静态成员函数可以调用类的静态成员函数吗?
        
                        可以。
           静态成员函数可以调用静态成员变量。
           非静态成员函数可以调用非静态成员变量。
           非静态成员方法可以调用静态成员变量。

十四.友元

        1.什么是友元
        
                友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
                友元分为:友元函数友元类。
        
        类的成员限定符限制的是类的成员,友元不是类的成员,不受成员限定符的限制。
        
        2.友元函数
        问题:现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要将operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。
class Date
{
public:
 Date(int year, int month, int day)
 : _year(year)
 , _month(month)
 , _day(day)
 {}
 // d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用
 // 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧
 ostream& operator<<(ostream& _cout)
 {
 _cout << _year << "-" << _month << "-" << _day << endl;
 return _cout;
 }
private:
 int _year;
 int _month;
 int _day;
};
         友元函数可以直接访问类的私有成员,它是定义在类外部普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
class Date
{
 friend ostream& operator<<(ostream& _cout, const Date& d);
 friend istream& operator>>(istream& _cin, Date& d);
public:
 Date(int year = 1900, int month = 1, int day = 1)
 : _year(year)
 , _month(month)
 , _day(day)
 {}
private:
 int _year;
 int _month;
int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
 _cout << d._year << "-" << d._month << "-" << d._day;
 return _cout;
}
istream& operator>>(istream& _cin, Date& d)
{
 _cin >> d._year;
 _cin >> d._month;
 _cin >> d._day;
 return _cin;
}
int main()
{
 Date d;
 cin >> d;
 cout << d << endl;
 return 0;
}
        说明:
                友元函数可访问类的私有和保护成员,但不是类的成员函数。
                友元函数不能用const 修饰。(没有this指针)
                友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
                一个函数可以是多个类的友元函数。
                友元函数的调用与普通函数的调用原理相同。
        3.友元类
    
                a.友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
                b.友元关系是单向的,不具有交换性。比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time。
                c.类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
友元关系不能传递
                d.如果B是A的友元,C是B的友元,则不能说明C时A的友元。
                e.友元关系不能继承。
class Time
{
 friend class Date; // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成
员变量
public:
 Time(int hour = 0, int minute = 0, int second = 0)
 : _hour(hour)
, _minute(minute)
 , _second(second)
 {}
 
private:
 int _hour;
 int _minute;
 int _second;
};
class Date
{
public:
 Date(int year = 1900, int month = 1, int day = 1)
 : _year(year)
 , _month(month)
 , _day(day)
 {}
 
 void SetTimeOfDate(int hour, int minute, int second)
 {
 // 直接访问时间类私有的成员变量
 _t._hour = hour;
 _t._minute = minute;
 _t._second = second;
 }
 
private:
 int _year;
 int _month;
 int _day;
 Time _t;
};

十五.内部类

        1.概念:

                如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。

                注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
        2.特性:
                a. 内部类可以定义在外部类的public、protected、private都是可以的。
                b. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
                c. sizeof(外部类)=外部类,和内部类没有任何关系。
class A
{
private:
static int k;
 int h;
public:
 class B // B天生就是A的友元
 {
 public:
 void foo(const A& a)
 {
 cout << k << endl;//OK
 cout << a.h << endl;//OK
 }
 };
};
int A::k = 1;
int main()
{
 A::B b;
 b.foo(A());
 
 return 0;
}

        

        
                

你可能感兴趣的:(C++,c++,开发语言)