草庐IT

c++ - 我认为下面的陈述不正确或者我遗漏了什么?

coder 2024-02-05 原文

以下段落摘自 Stroustup 书《The C++ Programming Language》(第三版)第 420 页:

Because a pointer to a virtual member (s in this example) is a kind of offset, it does not depend on an object’s location in memory. A pointer to a virtual member can therefore safely be passed between different address spaces as long as the same object layout is used in both. Like pointers to ordinary functions, pointers to nonvirtual member functions cannot be exchanged between address spaces.

我对本段的最后一句话提出异议。下面,您将找到一个代码片段,其中指向非虚拟成员函数的指针,foo()foo1(),在一个基数之间交换对象 a 和派生对象 b,没有问题。

不能做的是在派生类中重载基类中的任何函数,foo()foo1(),因为在这个在这种情况下,编译器将发出如下所示的错误。

#include <iostream>

class A
{
    int i;
    public:
    A() : i(1) {}
    void foo() { std::cout << i << '\n'; }
    void foo1() { std::cout << 2 * i << '\n'; }
};

class B: public A
{
    int j;
    public:
    B() : A(), j(2) {}
//  void foo() { std::cout << j << '\n'; }
};

int main()
{
    typedef void (A::* PMF)();
    PMF p = &B::foo;    //   error C2374: 'p' redefinition, multiple initialization
                        //   if foo() is overloaded in B.
    PMF q = &B::foo1;
    B b;
    (b.*p)();
    (b.*q)();

    A a;
    (a.*p)();
    (a.*q)();
}

最佳答案

这句话是正确的:在(标准)C++ 中,一个程序,或者说进程,只有一个地址空间。因此,正如 ulidtko 所指出的,这句话指的是在不同进程的地址空间之间交换指向虚拟成员函数与非虚拟成员函数的指针的可能性。

一个类的非虚拟成员函数 几乎是一个标准函数,带有一个指向您调用它的对象的隐式参数(this 指针)。因此,它会在加载时在您的进程地址空间中分配一些地址。它在您的地址空间中的确切位置当然取决于您的平台以及该成员函数是否是动态链接库的一部分。关键是,对于两个进程,它不一定是相同的地址。因此,将指针传递给另一个进程然后在另一个进程中执行这样的函数可能会“让你的机器着火 (TM)”。

虚拟成员函数仍然与非虚拟成员函数非常相似,因为“执行时跳转到内存中的某个地址并将其传递给您的 this 指针”,但它是通过虚函数表 (vtable) 而不是直接调用的。因此,指向虚成员函数的指针几乎只是对象虚函数表的索引。调用该函数然后沿着“获取对象指针,可能增加指针以获取对象的 vtable 并跳转到该表的给定索引处的地址,将对象本身的地址作为 这个指针'。因此,这种通过 vtable 的间接寻址使得在地址空间之间交换指向虚拟成员函数的指针起作用。

免责声明:我有点倾向于“我真的知道我在说什么”——这里的舒适区。因此,如果我过度简化了某些事情或更糟的是,从事散布虚假信息,请随意撕碎我的答案;)。

关于c++ - 我认为下面的陈述不正确或者我遗漏了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15122953/

有关c++ - 我认为下面的陈述不正确或者我遗漏了什么?的更多相关文章

  1. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  4. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  5. ruby - 在好的 Ruby 代码中没有注释是否被认为是可以接受的? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭5年前。Improvethisquestion我审查了一些用Ruby编写的专业代码,没有发现任何评论。代码读起来相当清晰,但没有self记录。我应该期望专业编写的Ruby代码有注释吗?或者,是否有一些Ruby原则认为注释不是必需的?

  6. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  7. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  8. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

  9. ruby - Ruby 中字符串运算符 + 和 << 的区别 - 2

    我是Ruby和这个网站的新手。下面两个函数是不同的,一个在函数外修改变量,一个不修改。defm1(x)x我想确保我理解正确-当调用m1时,对str的引用被复制并传递给将其视为x的函数。运算符当调用m2时,对str的引用被复制并传递给将其视为x的函数。运算符+创建一个新字符串,赋值x=x+"4"只是将x重定向到新字符串,而原始str变量保持不变。对吧?谢谢 最佳答案 String#+::str+other_str→new_strConcatenation—ReturnsanewStringcontainingother_strconc

  10. ruby - rails 3.2.2(或 3.2.1)+ Postgresql 9.1.3 + Ubuntu 11.10 连接错误 - 2

    我正在使用PostgreSQL9.1.3(x86_64-pc-linux-gnu上的PostgreSQL9.1.3,由gcc-4.6.real(Ubuntu/Linaro4.6.1-9ubuntu3)4.6.1,64位编译)和在ubuntu11.10上运行3.2.2或3.2.1。现在,我可以使用以下命令连接PostgreSQLsupostgres输入密码我可以看到postgres=#我将以下详细信息放在我的config/database.yml中并执行“railsdb”,它工作正常。开发:adapter:postgresqlencoding:utf8reconnect:falsedat

随机推荐