类和对象[ 构造函数(初始化列表)、static成员、explicit关键字、友元、内部类 ]

一、构造函数(初始化列表)

我们都知道构造函数的作用:使用类创建对象时,对对象进行初始化,但是我们所理解的初始化和真正的初始化是有所不同的

 1、构造函数体赋值:

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

  乍一看,我们会得出一个结论:这个就是构造函数进行初始化。但其实,这只是构造函数进行赋值罢了。因为初始化只能初始化一次,而构造函数体内可以进行多次赋值。这时我们就得引出今天的重要嘉宾:初始化列表 !

 2、初始化列表:

  初始化列表的作用才是将类中的成员变量初始化。

  使用方法:以 : 开始,不同的成员变量用 , 分割开,每个成员变量初始化格式是将成员变量放在前,后接 - 括号,括号中放的是想要初始化的值 。(我个人是这样理解的:初始化列表就是一个列表,[开始 , 分割换行]所以在最后一个成员变量后面不可以加任何符号)

  例:

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

 3、值得注意的知识点:

  ①初始化列表中每个成员变量只能初始化1

  ②以下类的成员变量必须在初始化列表中初始化:

     (1)引用类型的成员变量

     (2)const修饰的成员变量

     (3)自定义类型的成员变量且该类没有默认构造函数

  ③尽量使用初始化列表进行初始化(即使没有初始化列表,对于自定义类型而言,也会先使用初始化列表初始化)

  ④成员变量在类中的声明次序,就是初始化的顺序(与初始化列表中的顺序无关)

 4、explicit关键字(与强制类型转换有关):

  我们一定都见过这样的代码语句:

  double x = 5.5;

  int a = x; //实际上会将x强制类型转换成int类型的值存放在一个临时变量中,然后赋值给a

  内置类型能强转我们是知道的,那自定义类型呢?

  答:自定义类型也可以强转

  我们可以这样写:

calss A
{
public:
  //explicit A(int a = 15)  -----  用explicit关键字修饰构造函数后可以避免强制类型转换
  A(int a = 15)
  {
  _a = a;
  }
private:
  int _a;
};
int main()
{
  A aa(12);
}

上述是比较常见的书写方式,那这样呢?

calss A
{
public:
  A(int a = 15)
  {
  _a = a;
  }
private:
  int _a;
};
int main()
{
  A aa;
  aa = 20; //我们也可以用强转来解释这一行代码,但是如果想避免强转可以使用explicit关  
           //键字
}

二、static成员

 类中声明用static修饰的成员变量为静态成员变量,用static修饰的成员函数称之为静态成员函数

  1、使用方法:

   ①静态成员为所有类对象共享,不属于某个具体的对象,存放在静态区

   ②静态成员变量必须在类外定义,定义时不可加static(由①静态成员不属于对象推断得来)

   ③类静态成员用: 类::成员 或 对象.成员 的方式访问

   ④静态成员函数没有隐藏的this指针,因此也不能访问任何非静态成员

   ⑤静态成员也是类的成员,也要受到public、private、protected的限制

 2、计算创建了几次类对象:

class A
{
public:
  A()
  {
    ++_count;
  }
  A(const A& a)
  {
    ++_count;
  }

  ~A()
  {
    --_count;
  }

  static int Getcount()
  {
    return _count;
  }

private:
  static int _count;
};
int A::_count = 0;
void TestA()
{
  cout << A::Getcount()<<endl;
  A a1,a2;
  A a3(a1);
  cout << A::Getcount()<<endl;
}

   答案是:3次

三、友元

 1、友元函数:

  相信我们大家都知道输出输入流(<< >>)吧。那么,我们不妨大胆一点,如果我们把这两个操作符重载,要怎么操作?怎么使用?

  首先我们来看一下正常使用:

class A
{
public:
  A(int a = 5)
  {
    _a = a;
  }

private:
  int _a;
};
int main()
{
  A a1;
  cout<<a1._a<<endl;
}

   ①我们来进行重载:

class A
{
public:
  A(int a = 5)
  {
  _a = a;
  }
  ostream& operator<<(ostream& _cout)
  {
    //打印对象中的成员变量值
    _cout<<_a<<endl;
    Return _cout;
}
private:
  int _a;
}
int main()
{
  A a1;
  //使用输出流操作符
  //因为我们在使用操作符调用成员函数时会传递一个隐含参数this指针,这个
  //指针指向的是调用此函数的对象,所以这种写法和我们平时使用的有点不同
  a1<<cout;
}

   上面核心点在于:调用成员函数需要使用到隐含参数才可以访问到对象成员,所以格式会有限制

   ②那么问题又来了:如何才能像我们平时一样去使用呢

    友元函数登场!

class A
{
public:
  A(int a = 5)
  {
    _a = a;
  }
  //使用友元函数前面加个 friend
friend ostream& operator<<(ostream& _cout , const A& a)
private:
  int _a;
}

//友元函数
ostream& operator<<(ostream& _cout , const A& a)
{
  //打印对象中的成员变量值
  _cout<<a._a<<endl;
  return _cout;
}

int main()
{
  A a1;
  //打印
  cout<<a1.a;
}

   上面核心点在于:

   ①首先友元函数使用就是在前面加上一个friend,非常简单

   ②友元函数不属于类,所以友元函数也不是成员函数,需要传递相关的参数(包括调用函数的对象,因为不是成员函数没有this指针)

   ③同一个友元函数可以被多个类调用

   ④友元函数也不能用const修饰(因为友元函数不能被限定,所有的类都可以调用)

 2、友元类:

  既然存在友元函数,那么友元类的存在也就合情合理了。何为友元类?我们可以来类比一下友元函数:如果一个函数是友元函数,那么类中加上关键字friend后,这个函数在类中就可以访问类的私有成员变量!(就好比这个函数表明自己是其他类的朋友,那朋友就是用来索取的,所以这个函数就可以肆无忌惮的以朋友“friend”的名义肆无忌惮的使用类中的成员变量)。所以,友元类也是同理,一个类是另一个类的友元类,那么这个类只要愿意,是可以肆无忌惮的使用另一个类的成员函数以及被保护的成员变量。

  但是有一点需要注意,你是我的友元类,你可以肆无忌惮的调用我的资源,但是你的资源我无权操纵,因为朋友关系只是我单方面建立的,你并没有建立。(我说你是我的朋友,你可以随意从我这里拿东西,但是你没有承认我是你的朋友,那我别想拿你的东西!)

  所以,总结友元类:

   ①一个类若是另一个类的友元类,那么这个类就可以打着“friend”的名义去调用另一个类。

   ②友元类的关系是单向的(我说you are my friend,你可没说)

   ③友元类的关系不可传递(你是我朋友,我是他朋友,你跟他并不一定是朋友)

   ④友元类的关系不可继承

   代码:

class Time
{
  friend class Date;
public:
  time(int hour, int minute, int second)
  :_hour(hour)
  ,_minute(minute)
  ,_second(second)
  {}
private:
  int _hour;
  int _minute;
  int _second;
}
class Date
{
public:
  Date(int year,int month, int day)
  :_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;
}

   Date类是Time类的友元类 ->  Date 是 Time 的朋友 -> Date类 可以调用Time类中的等等。

四、内部类

 1、概念:如果一个类在另一个类的内部创建,那么这个类就是另一个类的内部类,另一个类就是外部类。但实际上,除了内部类是外部类的友元类之外:①两个类并没有包含与被包含的关系 ②外部类对内部类也没有优越于其他独立类的操作权限。

 2、特性:

  ①内部类可以定义在外部类中的public、protected、private

  ②外部类的大小就是整个类的大小,并不包含内部类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值