学习C++遇到的问题2:空的对象指针调用成员函数然后访问数据成员居然没报错?

学习C++遇到的问题2:空的对象指针调用成员函数然后访问数据成员居然没报错?
题目如图所示:
刚开始我想当然的认为用一个空的对象指针去调用一个函数会发生运行时错误,后来答案成功运行了。当我们调用的函数没有访问成员数据时应该是不会报错的。

img

之后,我又实验了一下两种情况,当空对象指针调用的函数中有用到成员数据时一个会报错,一个却没有报错,不太理解为什么。

#include <iostream>
using namespace std;
class Demo {
public:
    Demo() : count(0) { }
    void say2(const string &msg) {
        fprintf(stderr, "%s\n", msg.c_str());
        cout << this->count  << endl;
    }
    int count;
    
};
int main() {
    Demo* v;
    v->say2("hello world");
}

运行结果:

img

#include <iostream>
using namespace std;
class Demo {
public:
    Demo() : count(0) { }
    // ~Demo() { }
    void say2() {
        cout << this->count  << endl;
    }
    int count;
    
};
int main() {
    Demo* v;
    v->say2();
}

运行结果:

img

建议看一本老书,深入探索c++对象模型。
一般c++编译器,会把非静态类成员放在一起类似于c的结构,而把成员函数放在另外一个地方,被所有的这个类型的对象所共享
,每个类对象有个表,存放成员函数的地址。在调用这个成员函数是编译器会插入一个const T* ,就是this用以区分具体哪个类对象来调用它。因此因为函数不放在类对象里面,所以你用空的对象调用,只要不访问类成员就不会出错。

类本身就是一个作用域。从最基础的理解,数据结构是把一组相关的数据元素组织起来然后使用它们的策略。

尝试从编译层面理解 class struct 关键字,成员函数和成员变量,都在类作用域中声明,编译的时候,先编译成员的声明,再编译成员函数

为什么类外部不能直接使用成员变量?因为超出了作用域。

成员函数也是个函数,但是它定义在类的内部,就能随意调用作用域内的变量,当我不调用的时候,它就是个普通函数

更为常见是情况是,给成员函数加上 static 修饰,直接就能当做普通函数调用了

最后回到题目中, 为什么发生崩溃了,因为对象没有初始化,调用成员时,访问了非法的地址

这里也给新人一点建议,不太建议使用 gcc 编译器,默认的 gcc 编译参数,即使代码存在很明显的问题,也能给你编译通过,明显访问了非法的内存地址

微软的 visual studio 默认编译参数,你两种写法都会导致程序崩溃,程序改动了一点,因为不初始化指针对象,vs 上无法编译通过

img

其实电脑开机后物理内存的每个字节中都有值且都是可读写的,从来不会因为所谓的new、delete或malloc、free而被创建、销毁。区别仅在于操作系统内存管理模块在你读写时是否能发现并是否采取相应动作而已。操作系统管理内存的粒度不是字节而是页,一页通常为4KB。