C++(2)- 静态成员函数

在 C++ 中,静态成员函数(static member function)是与类相关联而不是与类的任何特定对象相关联的函数。静态成员函数有以下几个特点:

1. 声明和定义

静态成员函数使用 static 关键字声明。它们可以访问类的静态成员,但不能直接访问非静态成员(因为非静态成员属于具体的对象,而静态成员函数没有对象实例)。

声明

在类声明中使用 static 关键字声明静态成员函数:

1
2
3
4
class MyClass {
public:
static void myStaticFunction();
};

定义

在类外部定义静态成员函数时,不需要再次使用 static 关键字:

1
2
3
void MyClass::myStaticFunction() {
// 函数体
}

2. 访问静态成员函数

静态成员函数可以通过类名直接调用,也可以通过对象调用,但推荐使用类名调用以明确其静态特性。

1
2
3
MyClass::myStaticFunction();  // 通过类名调用
MyClass obj;
obj.myStaticFunction(); // 通过对象调用

3. 静态成员函数的特点

  • 无隐式 this 指针:静态成员函数没有隐式的 this 指针,因此不能直接访问非静态成员变量和非静态成员函数。
  • 共享数据:静态成员函数可以访问类的静态成员变量,这些变量在所有对象之间共享。
  • 全局作用域:静态成员函数在类的作用域内,但可以看作是全局函数,因为它们不依赖于任何特定的对象实例。

4. 示例

以下是一个简单的示例,展示了静态成员函数的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <string>

class MyClass {
public:
static int objectCount; // 静态成员变量

MyClass() {
++objectCount; // 每创建一个对象,计数加1
}

~MyClass() {
--objectCount; // 每销毁一个对象,计数减1
}

static void printObjectCount() {
std::cout << "Number of objects: " << objectCount << std::endl;
}
};

// 初始化静态成员变量
int MyClass::objectCount = 0;

int main() {
MyClass::printObjectCount(); // 输出: Number of objects: 0

{
MyClass obj1;
MyClass obj2;
MyClass::printObjectCount(); // 输出: Number of objects: 2
}

MyClass::printObjectCount(); // 输出: Number of objects: 0

return 0;
}

解释

  1. 静态成员变量objectCount 是一个静态成员变量,它在所有 MyClass 对象之间共享。
  2. 构造函数和析构函数:在构造函数中增加 objectCount,在析构函数中减少 objectCount
  3. 静态成员函数printObjectCount 是一个静态成员函数,它可以访问 objectCount 并打印当前的对象数量。
  4. 调用静态成员函数:通过类名 MyClass::printObjectCount() 调用静态成员函数,也可以通过对象调用,但推荐使用类名调用。

5. 静态成员函数的用途

  • 工具函数:静态成员函数可以用于实现与类相关的工具函数,这些函数不依赖于具体的对象实例。
  • 工厂方法:静态成员函数可以用作工厂方法,用于创建类的实例。
  • 全局状态管理:静态成员函数可以用于管理类的全局状态,例如计数器、配置选项等。

C++(1)- 虚函数

在 C++ 中,虚函数(virtual function)是实现多态的一种机制。通过虚函数,可以在派生类中重写(override)基类中的函数,从而在运行时根据对象的实际类型调用相应的函数。以下是关于 C++ 中虚函数的详细介绍和示例。

1. 基本概念

  • 虚函数:在基类中声明为 virtual 的成员函数。虚函数允许派生类重写该函数,从而实现多态。
  • 纯虚函数:在基类中声明为 virtual 并且没有实现的函数,形式为 virtual 返回类型 函数名() = 0;。含有纯虚函数的类称为抽象类,不能实例化。
  • 多态:通过基类指针或引用调用虚函数时,实际调用的是派生类中重写的函数,而不是基类中的函数。

2. 虚函数的声明和使用

声明虚函数

在基类中声明虚函数:

1
2
3
4
5
6
class Base {
public:
virtual void display() {
std::cout << "Base class display function" << std::endl;
}
};

派生类中重写虚函数

在派生类中重写基类的虚函数:

1
2
3
4
5
6
class Derived : public Base {
public:
void display() override {
std::cout << "Derived class display function" << std::endl;
}
};

3. 多态的实现

通过基类指针或引用调用虚函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>

class Base {
public:
virtual void display() {
std::cout << "Base class display function" << std::endl;
}
};

class Derived : public Base {
public:
void display() override {
std::cout << "Derived class display function" << std::endl;
}
};

int main() {
Base baseObj;
Derived derivedObj;

Base* basePtr = &baseObj;
Base* derivedPtr = &derivedObj;

basePtr->display(); // 输出: Base class display function
derivedPtr->display(); // 输出: Derived class display function

return 0;
}

4. 纯虚函数和抽象类

声明纯虚函数

在基类中声明纯虚函数:

1
2
3
4
class Base {
public:
virtual void display() = 0; // 纯虚函数
};

派生类中实现纯虚函数

在派生类中实现基类的纯虚函数:

1
2
3
4
5
6
class Derived : public Base {
public:
void display() override {
std::cout << "Derived class display function" << std::endl;
}
};

5. 构造函数和析构函数中的虚函数

  • 构造函数:虚函数在构造函数中不具有多态性,即在构造函数中调用虚函数时,只会调用当前类的虚函数,不会调用派生类的虚函数。
  • 析构函数:虚函数在析构函数中具有多态性,因此基类的析构函数通常声明为虚函数,以确保派生类的析构函数也能被调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

class Base {
public:
virtual ~Base() {} // 虚析构函数
virtual void display() {
std::cout << "Base class display function" << std::endl;
}
};

class Derived : public Base {
public:
~Derived() {} // 派生类的析构函数
void display() override {
std::cout << "Derived class display function" << std::endl;
}
};

int main() {
Base* basePtr = new Derived();
basePtr->display(); // 输出: Derived class display function
delete basePtr; // 调用 Derived 的析构函数

return 0;
}

6. 虚函数表(VTable)

C++ 编译器在内部使用虚函数表(Virtual Table, VTable)来实现虚函数的多态调用。每个包含虚函数的类都有一个虚函数表,表中存放了该类所有虚函数的地址。每个对象都有一个指向其类的虚函数表的指针(vptr),通过 vptr 可以找到对应的虚函数地址。