Bootstrap

C++ 类和对象 终篇

一 static成员:

静态成员变量是属于整个类的,而不是某个特定对象的。也就是说,所有对象共享同一个静态成员变量。它的特点包括:

非静态成员变量:

class A 
{
public:
    int _x; // 非静态成员变量
};

int main() 
{
    A a1, a2;
    a1._x = 5;
    a2._x = 10;
    std::cout << a1._x << std::endl; // 输出 5
    std::cout << a2._x << std::endl; // 输出 10
    return 0;
}

在这个例子中,a1a2 是两个不同的对象,它们各自有自己的 _x 变量,互不影响。a1._x 的值是 5,而 a2._x 的值是 10。

 静态成员变量:

class A 
{
public:
    static int _x; // 静态成员变量
};

// 在类外定义并初始化静态成员变量
int A::x = 0;

int main() 
{
    A a1, a2;
    a1._x = 5;
    std::cout << "a1._x: " << a1._x << std::endl; // 输出 5
    std::cout << "a2._x: " << a2._x << std::endl; // 输出 5

    a2._x = 10;
    std::cout << "a1._x: " << a1._x << std::endl; // 输出 10
    std::cout << "a2._x: " << a2.x << std::endl; // 输出 10
    return 0;
}

在这个例子中,x 是静态成员变量,它属于类 A,而不属于任何特定的对象。我们在类外定义并初始化了 A::x

总结:

共享性:静态成员变量在所有对象间共享,同一个类的所有实例都可以访问同一个静态成员变量。

类外初始化:静态成员变量必须在类外进行定义和初始化,确保它们只初始化一次

静态成员函数:

特点:

没有 this 指针:静态成员函数不能访问类的非静态成员变量或成员函数,因为不属于任何特定的对象所以它们没有隐含的 this 指针。

类范围内的函数:静态成员函数属于类的范围,可以在没有对象实例的情况下调用,直接通过类名调用。

访问静态成员变量:静态成员函数可以访问静态成员变量,因为它们同样属于类范围内。

代码演示:

class A 
{
public:
    A() 
   {
        ++n;
    }

    A(const A& a) 
    {
        ++n;
    }

    static int Getn() 
    {
        return n;
    }

private:
    static int n;
};

// 在类外定义并初始化静态成员变量
int A::n = 0;

int main() 
{
    A aa1; 
    A aa2;
    cout << A::Getn() << endl;
    return 0;
}

二 友元:

定义:

友元函数是一个定义在类外部的普通函数,但它被授予访问该类的私有和保护成员的特权。友元函数不是类的成员函数,但需要在类的内部声明,并使用 friend 关键字。

友元函数的特点:

  • 友元函数可以访问类的私有和受保护成员,但它本身并不是类的成员函数。

    • 友元函数在某种程度上是外部函数,但它们被赋予了访问指定类的私有和受保护成员的特权。
  • 友元函数不能被 const 修饰。

    • 尽管友元函数可以访问类的内部成员,但它们依旧是外部函数,因此不受类的成员函数的约束,如 const 限定。
  • 友元函数声明可以放在类的任何位置,不受访问控制符(如 publicprotectedprivate)的限制。

    • 无论是在 public 部分、protected 部分还是 private 部分,友元函数声明都可以放置,不影响其访问权限。
  • 一个友元函数可以是多个类的友元。

    • 这意味着同一个函数可以被多个类声明为友元,从而能够访问这些类的私有和受保护成员。
  • 友元函数的调用与普通函数相同。

    • 友元函数在调用时,不需要通过对象或类来调用,它们的调用方式与普通的非成员函数一致。

代码演示:

#include <iostream>
using namespace std;

class Point
{
public:
    Point()
    {
        _x++;
    }

    // 友元函数声明
    friend ostream& operator<<(ostream& out, const Point& p);

private:
    static int _x;
};

// 初始化静态成员变量
int Point::_x = 0;

// 友元函数定义
ostream& operator<<(ostream& out, const Point& p)
{
    out << Point::_x<<endl;
    return out;
}

int main()
{
    Point a;
    cout << a << 3 <<endl; // 输出Point类的静态成员变量_x的值
    //cout << 3 << endl; // 输出3
    return 0;
}

友元类:

 定义:

友元类在C++中是一个用于控制访问权限的重要机制。它们允许一个类的所有成员函数访问另一个类的私有和受保护成员。

代码演示:

class Time
{
    friend class Date;  // 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)
    {
        // 直接访问 Time 类的私有成员变量
        _t._hour = hour;
        _t._minute = minute;
        _t._second = second;
    }

private:
    int _year;
    int _month;
    int _day;
    Time _t;  // Date 类中有一个 Time 对象
};

特点:

  • 友元关系是单向的

    • 友元关系是单向的。比如,Date 类可以访问 Time 类的私有成员,但 Time 类不能自动访问 Date 类的私有成员。如果需要 Time 类也能访问 Date 类的私有成员,你必须在 Time 类中声明 Date 类为友元类。
  • 友元关系不能传递

    • 友元关系是不可传递的。即使 CB 的友元,BA 的友元,这并不意味着 C 自动成为 A 的友元。每一个友元关系需要显式声明。
  • 友元关系不能继承

    • 友元关系不会继承。如果一个类 A 声明了 B 为友元类,那么子类 B 的所有派生类并不会自动成为 A 的友元类。友元关系仅对直接声明它们的类有效。

三 内部类:

定义:

内部类是定义在另一个类的内部的类。它可以访问外部类的所有成员,包括私有成员。

特点:

  • 内部类可以定义在外部类的 publicprotectedprivate 区域。
  • 内部类可以直接访问外部类的 static 成员,不需要外部类的对象或类名。
  • 内部类的存在对外部类的大小没有任何影响

代码演示:

#include <iostream>
using namespace std;

class Product {
private:
    static int discount; // 静态成员变量,用于记录折扣
    int price;           // 非静态成员变量,记录价格

public:
    class Details {
    public:
        void show(const Product& p) {
            cout << "Discount: " << discount << "%" << endl;  // 访问静态成员变量
            cout << "Price: $" << p.price << endl;            // 访问非静态成员变量
        }
    };

    // 构造函数
    Product(int p) : price(p) {}
};

// 在类外定义并初始化静态成员变量
int Product::discount = 10;

int main() {
    Product::Details d; // 创建嵌套类 Details 的对象
    Product p(100);     // 创建 Product 类的对象,价格为 100
    d.show(p);          // 调用 Details 类的成员函数,显示 Product 的信息

    return 0;
}

四 匿名对象:

定义:

匿名对象在C++中是指那些在创建时没有被赋予一个变量名的对象。它们的主要特点是生命周期非常短暂,只在创建它们的那条语句中存在,随后就会被销毁。匿名对象的使用场景通常是为了临时操作,比如传递对象作为函数参数或者调用成员函数。

代码演示:

#include <iostream>
using namespace std;

class B
{
public:
    B(int b = 0)
        : _b(b)
    {
        cout << "B(int b)" << endl;
    }
    ~B()
    {
        cout << "~B()" << endl;
    }
    void display() const
    {
        cout << "Value: " << _b << endl;
    }
private:
    int _b;
};

int main()
{
    B(5).display(); // 创建一个匿名对象并调用其成员函数
    return 0;
}

让我们来主句分析:

  • B(5):

    • 这行代码创建了一个 B 类型的匿名对象。匿名对象意味着这个对象没有名字,也不会被存储在任何变量中。
    • 传递参数 5 给构造函数 B(int b),因此 _b 被初始化为 5
    • 构造函数 B(int b) 被调用,输出 "B(int b)"。
  • .display():

    • 匿名对象创建后,立即调用其成员函数 display()
    • display() 函数输出成员变量 _b 的值,即 "Value: 5"。
  • 对象销毁:

    • 由于匿名对象的生命周期仅限于该语句,在调用 display() 函数后,对象立即被销毁。
    • 析构函数 ~B() 被调用,输出 "~B()"。
;