欢迎光临
我们一直在努力

C++之类和对象下

在探构造函数

1.之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函数初始化还有⼀种⽅ 式,就是初始化列表,初始化列表的使⽤⽅式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成 员列表,每个"成员变量"后⾯跟⼀个放在括号中的初始值或表达式。

2.每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地⽅。

3.引⽤成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进⾏初始 化,否则会编译报错。

正确应该这样

4.如果构造函数的初始化列表里没写这个成员,就用声明时的缺省值;如果初始化列表里写了,就用初始化列表的值。

初始化列表里写了:

初始化列表没写:

5.尽量走初始化列表

  • 所有成员一定走初始化列表,你不写编译器也会补。
  • 初始化列表优先级 > 类内缺省值。
  • 内置类型:没初始化、没缺省值 → 值不确定。
  • 自定义类型:没初始化 → 调用默认构造,没有就报错。
  • 引用 /const/ 无默认构造的对象:必须手动写初始化列表。

看下一段代码

lass Time
{
public:
Time(int hour)
: _hour(hour)
{
cout << "Time()" << endl;
}
private:
int _hour;
};
class Date {
public:
Date()
: _month(2)
{
cout << "Date()" << endl;
}

void Print() {
cout << this->_year << "-"
<< this->_month << "-"
<< this->_day << endl;
}
private:
int _year;
int _month=5;
int _day=30;
//int& _x;
const int _y=1;
Time _t;
};

所有成员都走了初始化列表,但是Time类型没有合适的默认构造最后报错

6.初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序⽆关。

7.建议声明顺序和初始化列表顺序保持⼀致。

接下来我们来看一道题目

#include<iostream>
using namespace std;

class A
{
public:
A(int a)
:_a1(a)
,_a2(_a1)
{}

void Print() {
cout << _a1 << " " << _a2 << endl;
}
private:
int _a2 = 2;
int _a1 = 2;
};

int main()
{
A aa(1);
aa.Print();
}

你觉得这段代码的运行结果会是什么?

正确答案是D

类中按照声明顺序进⾏初始化,先声a2,然后是a1,初始化列表优先级 > 类内缺省值。

a2先拿a1的值,但是此时a1还没有值,所以a2 值不确定。

a1为传进来a的值,所以a1为1.

初始化列表总结

⽆论是否显⽰写初始化列表,每个构造函数都有初始化列表;

⽆论是否在初始化列表显⽰初始化成员变量,每个成员变量都要⾛初始化列表初始

类型转换

我们在c语言的学习中,接触过一些类型转换比如整型和浮点型之间的转换

在c++中也有类型的转换,其中就包括一下三种。

1.C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。

整形现在不能和类类型转换,因为没有相关内置类型为参数的构造函数。

应该这样就可以

接下来我们看

你觉得这个可以编译通过吗?

答案是不可以

对比上面就是多了引用,按理来说应该可以通过,但是不要忘记了,1是创造了一个临时变量,然后临时变量有有常性,要加const,之前那篇讲引用的时候讲到过,可以看下面这个图理解一下

那为什么c++要搞这个呢

就是为了类类型来准备

多参数的隐式类型转换要用花括号

2.构造函数前⾯加explicit就不再⽀持隐式类型转换。

3.类类型的对象之间也可以隐式转换,需要相应的构造函数⽀持。

class B
{
public:
B(const A& a)
:_b(a.Get())
{
}

private:
int _b = 0;
};

B类型和A类型产生了联系,也可以使用隐式类型转换

static成员

1.⽤static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进⾏初始化。静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区

⽤static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针。

2.静态成员函数:

  • 可以访问 类的静态成员变量、静态成员函数
  • 不能访问 类的非静态成员变量、非静态成员函数
  • 原因:静态函数没有 this 指针
  • 为什么不能访问非静态成员?

    • 非静态成员:属于每一个对象,每个对象都有自己独立的一份
    • 静态成员:属于整个类,所有对象共享一份
    • this 指针:指向当前调用函数的那个对象。
    • 静态成员函数是属于类、不属于任何对象的,所以它没有 this 指针。没有 this 指针,就不知道要访问哪个对象的非静态成员,编译器直接报错

    3.突破类域就可以访问静态成员,可以通过类名::静态成员 或者 对象.静态成员 来访问静态成员变量 和静态成员函数。

    4.静态成员也是类的成员,受public、protected、private 访问限定符的限制。

    因为私有无法从外部直接访问。

    5.静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员 变量不属于某个对象,不⾛构造函数初始化列表。

    3.友元

    • 正常情况下:类外不能访问 private 成员
    • 友元作用:给外部函数 / 类开 “后门”,让它能直接访问你的私有成员
    • 关键字:friend

    主要分为以下两种

    ① 友元函数

    外部函数,声明成友元 → 能访问类的私有成员

    ② 友元类

    另一个类,声明成友元 → 整个类都能访问私有成员


    友元函数

    在运算符重载那里说过。

    在外面创造函数,在类里面声明。

    然后接下来我们来看友元类

    友元类关系不能传递,如果A是B的友元, B是C的友元,但是A不是C的友元。

    有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多⽤。

    内部类

    内部类是定义在另一个类内部的类,是两个独立的类,仅「作用域嵌套」,无继承 / 友元关系!

    接下来我们来看一个内部类的代码

    你觉得这个sizeof(A)应该是多少呢?

    答案是4.

    因为静态成员变量,他的内存空间并不是储存在类里面,是存储在静态区。

    那么A的私有成员变量只有一个int所以是四个字节,进而一步说明内部类是⼀个独⽴的类,跟定义在 全局相⽐,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。

    另外一点内部类默认是外部类的友元类。也就是说内部类可以访问外部类的私有,但是外部类不能访问内部类的私有。

    内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使⽤,那么可以考 虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其 他地⽅都⽤不了。

    匿名对象

    ⽤ 类型(实参) 定义出来的对象叫做匿名对象,相⽐之前我们定义的 类型 对象名(实参) 定义出来的 叫有名对象

    匿名对象⽣命周期只在当前⼀⾏,⼀般临时定义⼀个对象当前⽤⼀下即可,就可以定义匿名对象

    这样就对于一些场景来说会非常方便

    我们先来看一个函数

    库里面sort函数翻译过来大概是这个意思

    我们要是只传两个值是默认从小到大排序,我们现在要实现从大到小排序

    greater<int>() 是 STL 提供的降序比较函数对象,我们要在第三个参数传入greater的对象。但是有了这个匿名对象就很方便,而且匿名对象⽣命周期只在当前⼀⾏,⼀般临时定义⼀个对象当前⽤⼀下即可。

    赞(0)
    未经允许不得转载:171主机测评 » C++之类和对象下
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址