在C语言中,数据和处理数据的操作(函数)是分开的。也就是说,C语言本身没有支持数据和函数之间的关联性。
C++用类描述抽象数据类型(abstract data type,ADT),在类中定义了数据和函数,把数据和函数关联起来。
对象中维护了多个指针表,表中放了成员与地址的对应关系。
class CGirl // 超女类CGirl。
{
public:
char m_name[10]; // 姓名属性。
int m_age; // 年龄属性。
// 默认构造函数和析构函数。
CGirl() { memset(m_name, 0, sizeof(m_name)); m_age = 0; }
~CGirl() { }
// 显示超女的姓名。
void showname() { cout << "姓名:" << m_name << endl; }
// 显示超女的年龄。
void showage() { cout << "年龄:" << m_age << endl; }
};
C++类中有两种数据成员:nonstatic、static,三种函数成员:nonstatic、static、virtual。
- 对象内存的大小包括:1)所有非静态数据成员的大小;2)由内存对齐而填补的内存大小;3)为了支持virtual成员而产生的额外负担。
- 静态成员变量属于类,不计算在对象的大小之内。
- 成员函数是分开存储的,不论对象是否存在都占用存储空间,在内存中只有一个副本,也不计算在对象大小之内。
- 用空指针可以调用没有用到this指针的非静态成员函数。
- 对象的地址是第一个非静态成员变量的地址,如果类中没有非静态成员变量,编译器会隐含的增加一个1字节的占位成员。
我将给出一个简单的C++示例,它展示了如何定义一个类、初始化成员变量、使用构造函数和析构函数、以及如何通过对象调用成员函数。这个例子将涵盖静态和非静态成员的使用,并且会展示如何调用非静态成员函数,即使是通过空指针(尽管这通常不推荐,因为它是不安全的)。
这里是一个名为 CGirl
的类,包含了基本的构造函数、析构函数和一些成员函数:
#include <iostream>
#include <cstring>
using namespace std;
class CGirl {
public:
char m_name[10]; // 姓名属性
int m_age; // 年龄属性
static int girlCount; // 静态成员,记录对象数量
// 默认构造函数
CGirl() {
memset(m_name, 0, sizeof(m_name));
m_age = 0;
girlCount++; // 每创建一个对象,girlCount 加一
}
// 析构函数
~CGirl() {
girlCount--; // 对象销毁时,girlCount 减一
}
// 显示超女的姓名
void showName() const {
cout << "姓名:" << m_name << endl;
}
// 显示超女的年龄
void showAge() const {
cout << "年龄:" << m_age << endl;
}
// 静态成员函数,显示超女的总数
static void showGirlCount() {
cout << "超女总数:" << girlCount << endl;
}
};
// 静态成员初始化
int CGirl::girlCount = 0;
int main() {
CGirl girl;
strcpy(girl.m_name, "Alice");
girl.m_age = 28;
girl.showName();
girl.showAge();
CGirl::showGirlCount(); // 显示静态成员
// 空指针调用示例(不推荐,仅为演示)
CGirl* pGirl = nullptr;
// 虽然下面的代码技术上是可能的,但在实际应用中是危险的,并应避免
// pGirl->showName(); // 这将导致运行时错误,因为涉及到this指针的访问
return 0;
}
在这个示例中:
CGirl
类包含两个非静态成员 (m_name
和m_age
) 和一个静态成员 (girlCount
)。- 静态成员函数
showGirlCount
可以在没有类实例的情况下调用,用来显示创建的CGirl
对象数量。 - 示例中的
main
函数创建了一个CGirl
对象,设置了姓名和年龄,并调用了成员函数显示这些信息。 - 对于空指针的调用,我添加了注释说明这种做法的潜在危险,实际编码中应避免使用空指针调用成员函数。
通过这个示例,可以看出C++如何在类中将数据和函数关联起来,以及如何管理静态和非静态成员。