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成员而产生的额外负担。
静态成员变量属于类,不计算在对象的大小之内。
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class CGirl // 超女类CGirl。
{
public:
char m_name[3]; // 姓名属性。
int m_bh; // 编号属性。
static int m_age; // 年龄属性。
// 默认构造函数和析构函数。
CGirl() { memset(m_name, 0, sizeof(m_name)); m_age = 0; }
~CGirl() { }
// 显示超女的姓名。
//如果是空指针调用,则this指针为空,会报错,需要加上代码 if (this == nullptr) return;
void showname() { if (this == nullptr) return; cout << "姓名:" << this->m_name << endl; }
// 显示超女的年龄。
void showage() { cout << "年龄:" << m_age << endl; }
};
int CGirl::m_age; //静态成员函数的初始化
int aaa; //全局变量
void func() {} //普通函数
int main()
{
CGirl g;
cout << "对象g占用的内存大小是:" << sizeof(g) << endl;
cout << "对象g的地址是:" << (void*)&g << endl;
cout << "成员变量m_bh的地址是:" << (void*)&g.m_bh << endl;
cout << "成员变量m_name的地址是:" << (void*)&g.m_name << endl;
cout<<"静态成员变量和全局变量的地址是在一起的"<<endl;
cout << "成员变量m_age的地址是:" << (void *)&g.m_age << endl;
cout << "全局变量aaa的地址是:" << (void*)&aaa << endl;
cout<<"成员函数的地址和普通函数的地址在一起"<<endl;
printf("成员函数showname的地址是:%p\n", &CGirl::showname);
printf("成员函数showage的地址是:%p\n", &CGirl::showage);
printf("函数func()的地址是:%p\n", func);
cout<<"用空指针可以调用没有用到this指针的非静态成员函数。"<<endl;
CGirl* g1 = nullptr;
g1->showname();
}
- 类的成员函数的地址和普通函数的地址在一起。
- 类的静态变量地址和全局变量的地址在一起。
- 类的内存空间计算的是类的非静态成员变量的地址空间。
用空指针可以调用没有用到this指针的非静态成员函数。
在类的成员函数中,操作类的非静态成员变量需要this指针(this.可以不用写,编译器会添加)
也就是说:在没有创建对象的情况下,访问非静态成员变量就是访问空指针。(this指针为空指针)
在调用类的成员函数showname时,调用了this指针,用来访问成员变量m_name.
但是,对象g1为空,导致访问了空指针this,导致程序退出,后面的输出语句就没有执行了。
完善由于没有创建对象,访问成员变量,导致程序退出的BUG