【C++】匿名对象 | explicit | static静态成员 | 友元

匿名对象

有些情况下,我们创建变量只是临时用一用,以后不会再用到了。这时,如果创建变量还要起名字,是不是很多余?

对此,C++引入了 匿名对象 供临时使用。

例如:如果我们创建对象slt,仅仅是为了调用一次Sum_Solution(),那不如用匿名对象。

【C++】匿名对象 | explicit | static静态成员 | 友元_第1张图片

匿名对象:指在没有被命名的情况下创建的临时对象。

格式:类名( )

说明:

1.匿名对象的生命周期只在本行。也就是说,一旦语句执行完,会调用匿名对象的析构函数,销毁它。

不信我们来验证下,看看是不是执行完立马销毁:

class Date
{
public:
    Date(int year)
        :_year(year)
    {
        cout << "Date()" << endl;
    }
    ~Date()
    {
        cout << "~Date()" << endl;
    }
private:
    int _year;
};
int main()
{
    Date (2000);
    Date d1(1000);
    Date d2(1000);
    Date d3(1000);
​
    return 0;
}

结果:

【C++】匿名对象 | explicit | static静态成员 | 友元_第2张图片

补:

创建匿名对象后,编译器可能会报警告,这是正常的。

【C++】匿名对象 | explicit | static静态成员 | 友元_第3张图片

explicit关键字

作用:explicit修饰构造函数,可以禁止类型转换。

在进一步讲解explicit之前,我们先来回顾一下:什么是类型转换?

想一想,Date d1=2022,我们是不是把一个int类型的值赋给一个Date类型的对象?

能够赋值成功,是因为其间默默进行了类型的转换。

细究来说,这两种创建对象的方式是不一样的:

Date d1(2022);   //直接调用构造函数
​
Date d2 = 2022;   //本质是一步(隐式)类型转换:2022从int类型转成Date类型

第二种方式可以视为3步:先构造,再拷贝构造,然后编译器优化,最终结果才是调用了构造函数。

2022先构造出一个临时对象(Date类型的2022),再拷贝给d2,此过程会被优化,以提高效率。

如果不想让下面的隐式类型转换发生,那就用explicit修饰构造函数。

class Date
{
public:
    explicit Date(int year)
    {
        _year = year;
    }
private:
    int _year;
};
​
int main()
{
    Date d1(1000);  //d1不受影响
    Date d2 = 1000;  //d2因涉及类型转换,初始化失败
    return 0;
}

无法转换:

【C++】匿名对象 | explicit | static静态成员 | 友元_第4张图片

static静态成员

如果我想要知道A类型的对象创建了多少个,要怎么办呢?

其实可以创建一个全局变量count来计数,但是,这种方式的缺点在于:

因为是全局的,人人都可以访问。

我们想要的count是:与A捆绑起来,别人访问不了,这个count就专门为A计数。

对于这个问题,在学习了static静态成员之后,我们就知道要怎么处理了。

概念:

声明为static的类成员称为类的静态成员

用static修饰的成员变量,称之为静态成员变量;

用static修饰的成员函数,称之为静态成员函数。

注:静态成员变量一定要在类外 进行 定义/ 初始化。

像这样:

class A
{
private:
    static int count;  //类里声明
};
​
int A::count = 0;     //类外初始化

了解:为什么静态成员一定要在类外初始化?

因为静态成员属于整个类,它被所有的对象所共享。

如果放在类里面初始化,当有多个对象存在时,每个对象里都含一份该静态成员,造成矛盾。

说明:

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

class Date
{
private:
    static int _year;  //_year在静态区
    int _month;        //_month在对象里面。若对象在栈区,它就在栈区。
};

2.静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明。

3.怎么访问静态成员?

➡️如果它是公有的:可用 类名::静态成员 或者 对象.静态成员 来访问。

class A
{
public:
    A (){
        count++;
    }
    static int count;  
};
​
int A::count = 0;  
​
int main()
{
    A a1;
    cout << A::count << endl;  //用类域来访问
    cout << a1.count << endl;  //用对象来访问。这里不是说在a1里找,只是帮助突破类域去找
    return 0;
}

➡️如果是私有的:通过公有的函数来访问。

class A
{
public:
    A(){
        count++;
    }
    int GetCount() {
        return count;   //可以返回count的值
    }
    
private:
    static int count;  
};
​
int A::count = 0;  
​
int main()
{
    A a1;
    cout << a1.GetCount() << endl;  //通过GetCount()来访问count
    return 0;
}

4.静态成员函数没有隐藏的this指针,仅能访问静态的成员变量,不能访问任何非静态成员。

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

友元

什么是友元

类的私有成员,一般情况下,外界是无法访问的。但实际上,private / protected并非是一堵密不透风的墙,

它对外开了个小口子,我们可以通过小口子访问私有成员。这个小口子就是友元。

友元是C++中的一种关系:像朋友一样亲密到可以访问私人空间的关系。发生在函数和类之间 or 类和类之间。

通过友元的关系,可以让一个函数or类 访问另一个类中的私有成员(private / protected)。

关键字:friend

分类:友元函数 友元类

➡️友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,

不属于任何类,但需要在类的内部声明。

声明格式:friend 类型 函数名 (参数);

例:

class A
{
public:
    A() {
        a = 10;
  }
private:
    int a;
    friend void Print(const A& obj);   //友元的声明
};
​
void Print(const A& obj) {
    printf("%d", obj.a);   //访问了私有成员a
}
​
int main()
{
    A a1;
    Print(a1);
    return 0;
}

结果:

说明:

1.友元函数可访问类的私有和保护成员,但不是类的成员函数。

2.友元函数不能用const修饰。

3.友元函数可以在类定义的任何地方声明,不受类访问限定符限制。

4.一个函数可以是多个类的友元函数。

5.友元函数的调用与普通函数的调用原理相同。

➡️友元类

我们不仅可以将一个函数声明为一个类的朋友,也可以将一个类声明为另一个类的朋友。

这就是友元类。

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

声明格式:friend class 类名;

示例:

class A;   //注意:Print之前要声明一下A!
​
class Print
{
public:                           
    void print(const A& obj);    //如果前面没有声明A,这里会不知道A是什么,导致报错
};
​
class A
{
public:
    A() {
        a = 10;
  }
private:
    int a;
    friend class Print;
};
​
//类外定义print
void Print::print(const A& obj) {
    printf("%d", obj.a);
}
​
int main()
{
    A a1;
    Print p;
    p.print(a1);
    return 0;
}

结果:

说明:

1.友元关系是单向的,不具有交换性。

声明A是B的友元,不代表B也是A的友元。

2.友元关系不能传递。

如果C是B的友元, B是A的友元,则不能说明C是A的友元。

3.友元关系不能继承,这个在继承那边再详说。

最后,友元能少用就少用!

虽说友元有助于数据的共享,但它也有副作用:打破了封装,会破坏信息的隐蔽性。

内部类

(了解)

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。

如:

class Outside
{
private:
    int a;
​
    class Inside
    {
    private:
        int b;
    };
};

内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。

外部类对内部类没有任何优越的访问权限。

说明:

1.内部类可以定义在外部类的public、protected、private都是可以的。

2.注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。

3.内部类天生就是外部类的友元。但是外部类不是内部类的友元。

class Outside
{
private:
    static int a;
    int b;
​
    class Inside    
    {
    public:
        void Print(const Outside& obj) {
            cout << a << endl;          //√,可以直接访问外部类中的static成员
            cout << obj.b << endl;      //√
        }
    private:
        int b;
    };
};

4.sizeof(外部类)=外部类,和内部类没有任何关系。

我们来证明一下:

class Outside
{
private:
    int a;
​
    class Inside
    {
    private:
        int b;
    };
};
​
int main()
{
    cout << sizeof(Outside);
    return 0;
}

结果:

可见,Inside不在Outside里。

实际上,它们是并列的关系,只是你从外部访问Inside,要受到Outside类域的限制。

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