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

时间:2016-01-06 13:02:42

标签: c++

我正在处理的代码:

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

Sample.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

Sample.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]没有&#t; t存在)。

但是,它仍会调用tellname(),即使它所称的实例也不存在。它只是认为其_name字段为空。

这怎么可能?

3 个答案:

答案 0 :(得分:5)

这只是未定义的行为,C ++没有任何要求,因此“任何事情都可能发生”。你所看到的只是一个巧合,毫无价值的理由:下次你运行它可能会崩溃,显示nyan cat等等。

答案 1 :(得分:3)

i从1到4包含,因为tellname是const,test[4].tellname()Sample::tellnameSample是未定义的结构,因此“名称:”是正确打印的,然后打印test[4]._name中的内存,幸运的是test[4]._name*指向的内存非空,甚至是结束字符串char。

所以,你很幸运。

答案 2 :(得分:3)

听起来你在想为什么要调用这个函数。在内存中,结构不包含其中的函数。相反,函数的一个副本放在可执行文件的某个位置。因此,当您致电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;
}