是否可以从不存在的实例调用方法?

Is it possible to call a method from an instance that doesn't exist?

本文关键字:实例 调用 方法 不存在 是否      更新时间:2023-10-16

我正在处理的代码:

我有以下代码(在main.cpp中有一个关于索引的错误):

样本.hpp:

#ifndef SAMPLE_HPP
# define SAMPLE_HPP
# include <iostream>
# include <string>
class Sample{
public:
    Sample(void);
    ~Sample(void);
    void    tellname(void) const;
private:
    std::string     _name;
};
#endif

示例.cpp:

#include <iostream>
#include "Sample.hpp"
Sample::Sample(void){
    this->_name = "testname";
    return;
};
Sample::~Sample(void){
    return;
}
void    Sample::tellname(void) const{
    std::cout << "Name : " << this->_name << std::endl;
    return;
}

main.cpp

#include "Sample.hpp"
int     main(void){
    int     i;
    Sample  *test;
    test = new Sample[4];
    i = 0;
    while (i++ < 4)          // I know : i++; shouldn't be here
        test[i].tellname();
    delete [] test;
    return 0;
}

如果我编译它,我会得到以下输出:

Name : testname
Name : testname
Name : testname
Name :

我的问题是:

关于最后一行,它调用了一个方法(void Sample::tellname(void),但来自不在表范围内的实例(test[4]不存在)。

但是,即使从中调用tellname()的实例不存在,它仍然会调用它它只是认为它的_name字段为空。

这怎么可能?

这只是一个未定义的行为,C++没有对其施加任何要求,因此"任何事情都可能发生"。您所看到的只是一个巧合,没有任何理由:下次运行时,它可能会崩溃,显示nyan-cat等等。

听起来您想知道为什么要调用该函数。在内存中,结构不包含其内部的函数。相反,函数的一个副本被放置在可执行文件的某个位置。因此,当您调用test[4].tellname()时,实际发生的情况是:地址test + (4 * sizeof(Sample))被传递给函数tellname()。该地址的值未定义。

下面是一个例子,让你了解正在发生的事情:

#include <iostream>
struct astruct {
    int i = 0;
    void prnt()
    {
        std::cout << i << 'n';
    }
};
struct bstruct {
    int y = 100;
};
int main()
{
    bstruct b;
    ((astruct*)&b)->prnt();
    getchar();
    return 0;
}

这里,prnt()在幕后传递bstruct的地址,并将其视为astruct的地址,因为bstruct中的第一个值是100,所以它打印100。你甚至可以将其简化为:

#include <iostream>
struct astruct {
    int i = 0;
    void prnt()
    {
        std::cout << i << 'n';
    }
};
int y = 100;
int main()
{
    ((astruct*)&y)->prnt();
    getchar();
    return 0;
}

i从1变为4 include,因为tellname是const,test[4].tellname()Sample::tellname,而Sample是一个未定义的结构,所以"名称:"正确打印,然后打印test[4]._name中的内存,幸运的是,test[4]._name*指向的内存不是null,甚至是一个结束字符串char。

所以,是的,你很幸运。