首页 > 编程语言 >C++对象模型:g++的实现(四)

C++对象模型:g++的实现(四)

时间:2022-10-31 10:59:11浏览次数:38  
标签:const 函数 getInt ++ 模型 C++ int 成员 指针

这篇博客开始总结《深度探索C++对象模型》的第四章,即C++中成员函数(除了构造函数和析构函数)相关的内容。介绍了C++类中的成员函数,包括常规成员函数、虚函数、静态函数。
其实我一直犹豫要不要写这一篇,因为在书中讲到多重继承下的虚函数时只是说实现很复杂,并没有具体讲有什么样的实现,我个人也因为技术力的原因没办法总结出g++实现的多重继承下的虚函数实现,只能通过调试软件管中窥豹。但我最终还是决定,权当给自己巩固的机会。

C++类中各种成员函数

非静态(非static)、非虚(非virtual)成员函数

这是最常规的一种成员函数,必须通过其绑定的对象或指针调用。

// test20.cpp
#include <cstdio>

class Test20 {
public:
    explicit
    Test20(int i)
        : m_i(i)
    {}

    int getInt() const { return m_i; }
    void setInt(int i) { m_i = i; }

private:
    int m_i;
};

int main() {
    Test20 t20(1);
    std::printf("%d\n", t20.getInt());
    t20.setInt(2);
    std::printf("%d\n", t20.getInt());
    Test20* pt20 = &t20;
    pt20->setInt(3);
    std::printf("%d\n", t20.getInt());
}

// Output:
//  1
//  2
//  3

实际上,编译器会将这种成员函数改写为非成员函数,并在函数的参数列表前面加一个类型为Test20* const的形式参数(如果成员函数加了const关键词则形参类型为const Test20* const),参数名为this。而且,在成员函数内所有对于该类所有的成员函数、成员变量的操作都通过this指针来进行。以Test20::setInt为例,改写之后就变成了:

void setInt(Test20* const this, int i) {
    this->m_i = i;
}

同时,为了放置名字冲突,编译器还会对函数的名字进行修饰,包括在前面添加其命名空间信息,其后添加参数信息等,这里就不详细展开了。

虚函数

为了支持多态,C++引入了虚函数这一概念。对于虚函数的调用会转化为对于虚函数表中某一表项内填写的函数指针的调用。
如下面的调用:

ptr->virtalFunc();

实际上会转化为:

// C++伪码
(ptr->vptr[1])(ptr);

其中ptr为指向某一对象的指针,virtualFunc为对象的某个virtual的成员函数,vptr为其虚函数表,1virtualFunc这个虚函数在虚函数表中的下标。
注意,只有使用指针和引用调用虚函数时才会表现出多态性(也就是从虚函数表中取函数的实际地址然后调用),而使用对象调用一个虚函数,即便其被声明为一个虚函数,也只是被当作常规函数调用,不会展现多态性(也就是不会从虚函数表中取得实际函数地址)。

// test21.cpp
#include <cstdio>

class Test21 {
public:
    explicit
    Test21(int i)
        : m_i(i)
    {}

    virtual
    int getInt() { return m_i; }
private:
    int m_i;
};

void call(Test21& t21) {
    int i = t21.getInt();
}

int main() {
    Test21 t21(1);
    int i = t21.getInt();
    call(t21);
    Test21* pt21 = &t21;
    i = pt21->getInt();
}

img
img
可以看到在main函数中使用t21这个对象调用虚函数getInt()直接call了函数真实地址,没有多态性;而使用pt21这个指针调用虚函数则从虚表中取出了虚函数的地址,然后call这个地址,会有多态性。而在call函数中,使用引用t21也时从虚表中取得的虚函数地址。
关于继承体系下的虚函数会在下个博客讲。

静态成员函数

对于静态成员函数,编译器不会改变其形参列表,也就是说不会传入一个名为this的、指向类的一个实例的指针。所以静态成员函数一般通过类名直接调用,或是使用类的实例对象/指针/引用调用,但和使用类名直接调用不会有区别,也不会传入this指针。
而且因为静态函数不传入this指针,所以静态函数内不能直接读写非静态成员变量和非静态成员函数(因为不知道其绑定的对象)。同时,静态函数也不能定义为const,因为其他成员函数定义为const时为了限定this指针,而静态成员函数不传入this指针,定义为const也就没有意义。

// test22.cpp
#include <cstdio>

class Test22 {
public:
    Test22(int i)
        : m_i(i)
    {}

    static
    void staticMethod() {
        std::printf("static member %d\n", s_i);     // OK
        // std::printf("commom member %d\n", m_i);  // ERROR
        anotherStaticMethod();                      // OK
        // commomMethod();                          // ERROR
    }

    static
    void anotherStaticMethod() {
        std::printf("Test::anotherStaticMethod()\n");
    }

    void commomMethod() {
        std::printf("Test22::commomMethod()\n");
    }

private:
    int m_i;
    static const int s_i;
};

const int Test22::s_i = 2;

int main() {
    Test22 t22(1);
    t22.staticMethod();     //OK
    Test22::staticMethod(); // OK
}

// Output
//  static member 2
//  Test::anotherStaticMethod()
//  static member 2
//  Test::anotherStaticMethod()

这篇博客就先总结到这里,关于虚函数的详细实现和成员函数指针等内容就放到后续的博客中吧。

标签:const,函数,getInt,++,模型,C++,int,成员,指针
From: https://www.cnblogs.com/lycpp/p/16843544.html

相关文章

  • C++——STL库——reverse、remove、remove_if
    1.reverse函数使用函数功能:将序列[first,last)的元素在原容器中颠倒重排,包含在algorithm库中reverse没有返回值时间复杂度为O(n)示例1:交换vector容器中元素的顺序vect......
  • C/C++ Note
    本文作为学习笔记,并不作商业用途。如下文内容有侵权等行为请联系博主删除==========================================================BitwiseOperationSimpleTalkC......
  • C++Builder(BCB)6.0若干提示、编程须知
    1、【工具——编辑器选项】可以设置代码编辑窗口的一些选项,比如设置字体和大小,【Tab键停留】和【空白缩进】默认可以改为4(对笔记本小屏幕很重要),等等。2、代码编辑有用的......
  • QML 怎么调用 C++ 中的内容?
    以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「englyf」https://mp.weixin.qq.com/s/z_JlmNe6cYldNf11Oad_JQ先说明一下测试环境编译器:vs2017x64开发......
  • 什么是JAVA内存模型
    前言在并发编程中,当多个线程同时访问同一个共享的可变变量时,会产生不确定的结果,所以要编写线程安全的代码,其本质上是对这些可变的共享变量的访问操作进行管理。导致这种不......
  • C++11绑定器bind及function机制
    前言之前在学muduo网络库时,看到陈硕以基于对象编程的方式,大量使用boost库中的bind和function机制,如今,这些概念都已引入至C++11,包含在头文件<functional>中。本篇文章主要......
  • C++求高精度pi(2)高斯-勒让德算法
    C++分析参考目前求π的算法中哪种收敛最快?-知乎(zhihu.com)中@byoshovel答主的回答,有这些比较容易想到的方法对于我们的任务来说,拉马努金公式和加强鬼畜公式和BBP......
  • Select模型
    Select与阻塞模式不同,Select模型管理多个Socket,同个select帮助监听socket是否发送事件,未发生的就删除掉#include<iostream>#include"Init.h"usingnamespacestd;In......
  • 生动说明Transformer,BERT,预训练模型的含义和关系
    很多知识,尽管在学会了之后发现原来是多么的简单,但是当你刚接触的时候则是完全一头雾水。在我学习自然语言处理的入门教程时,很多教程都把Transformer和BERT连在一起讲,并......
  • 《Effective C++:改善程序与设计的55个具体做法》阅读笔记 5——实现
    条款26:尽可能延后变量定义式的出现时间尽可能延后变量定义式的出现时间,因为有些变量定义了,可能未被使用,如“异常抛出,导致很多代码没有运行,这就有可能导致定义的变量未......