首页 > 编程语言 >深度探索C++对象模型——第二章

深度探索C++对象模型——第二章

时间:2022-11-29 23:24:27浏览次数:35  
标签:C++ public 编译器 Base 深度 拷贝 第二章 class 构造函数

第二章 构造函数语意学

Default constructor的构造操作

带有Default constructor的成员类对象

C++合成的默认构造函数是面向编译器的而不是面向程序员的,只会合成编译器需要的对象而非程序员需要的对象,比如下面这个例子:

class Foo {
public:
  Foo() {
    std::cout << "Foo default ctor\n";
  }
};

class Base {
public:
  Foo foo;
  char *str;
};

int main() {
  Base b;
  if (b.str == 0) std::cout << "str not init\n";
  return 0;
}

编译器会产生默认构造函数初始化Foo但不会初始化str

如果一个类中包含的多个成员类对象有构造函数,编译器会生成默认构造函数,按照成员类对象声明的顺序进行初始化。

带有虚函数的基类

带有虚函数的类会生成默认的构造函数,应为在函数的编译器期间需要通过构造函数生成虚指针,通过虚指针生成虚表,否则在运行期间无法执行动态绑定。

带有虚继承的类

给带有虚基类的类生成默认构造函数,从而可以访问虚继承的父类的成员。

Copy Constructor操作

当合成的拷贝构造函数进行拷贝的时候,一个类的虚指针会显式的指向自己的虚表,而不是指向右侧对象的虚表。

class Base{
public:
    virtual void func();
};
class Derived : public Base {
public:
    void func() override;
};
Base b;
Derived d;
d = b;	//最终d的虚表指向的是b的虚表

bitwise copy不会出现的情况:

  1. 一个类的成员类中含有拷贝构造函数(编译器自动合成的也算)
  2. 一个类继承的父类中有拷贝构造函数
  3. 一个类有虚函数时
  4. 一个类继承串链中有虚基类时

因此对于虚指针的拷贝不能执行简单bitwise copy

bitwise copy是一种浅拷贝,对于拷贝的对象执行memcpy或者类似的操作,直接拷贝对象的指针,但是对于指针指向的内容不进行拷贝。

如果是同种类之间的赋值可以直接使用bitwise copy但是如果是不同类之间的赋值并且这个类是一个虚继承的子类时就不能使用bitwise copy,编译器会自动合成拷贝构造函数。

class Animal{...};
class Racoon : public virtual Animal {...};
class RedPanda : public Racoon {...};
Racoon a;
RedPanda b;
b = a;	//需要memeberwise,bitwise copy已经不够用了
Racoon c = a;	//bitwise copY完全够用
Racoon *pta;
Racoon pb = &pta;	//应为不知道pta具体指向的类型,只能拷贝Racoon的部分。

NRV优化

当给类加入拷贝构造函数时候编译器会执行NRV(named return value) 优化。没有的话则不执行。

class X {
    X();
};
X bar() {
    X xx;
    return xx;
};
X x = bar();	//这段代码中如果没有拷贝构造函数会进行宝贝构造两个临时变量等价于下面这段代码

X bar() {
    X xx;
    return xx;
}
X tmp = xx;
X x = tmp;	//这样做会影响程序的性能

但是加上拷贝构造函数之后,上面的代码就可以优化为:

X bar(X &result) {
    X xx;
    result(xx);
};

经过优化之后只需要进行一次构造函数。

如果一个类的成员都是trival类型,编译器会自动生成默认的拷贝构造函数,当我们自己声明拷贝构造函数的时候直接使用memset进行初始化效率更高也更快。

class Point3d {
public:
  Point3d(float x, float y, float z);
  Point3d(const Point3d &rhs) {
    _x = rhs._x;
    _y = rhs._y;
    _z = rhs._z;
  }
	//下面这种方式初始化效率更高
  Point3d(const Point3d &rhs) {
      memsett(this, &rhs, sizeof(Point3d));
  }
private:
  float _x, _y, _z;
}

但是如果一个类含有类成员或者是虚函数就不能在使用memset进行初始化,这样做会把类的虚指针也初始化掉。

class Base {
public:
  Base() {
    std::memset(this, 0, sizeof(Base));
  }
    //这段代码等效于
  Base() {
      _vptr_Base = _vtbl_Base;
      memset(this, 0, sizeof(Base));	//将vptr初始化为0
  }
  virtual void func();
  virtual ~Base();
private:
  int a;
};

标签:C++,public,编译器,Base,深度,拷贝,第二章,class,构造函数
From: https://www.cnblogs.com/gxsoar/p/16937074.html

相关文章

  • c++ trivial, standard layout和POD类型解析
    目录1.trivial类型2.standardlayout类型3.集大成者,POD(PlainOldData)类型4.测试代码1.trivial类型占用一片连续的内存,编译器可以重排成员变量的顺序或者增加一些pa......
  • 【最详细易懂】C++和Lua交互总结
    一、Lua与C++的交互机制——Lua堆栈Lua和C++的交互机制的基础在于Lua提供了一个虚拟栈,C++和Lua之间的所有类型的数据交换都通过这个栈完成。无论何时C++想从Lua中调用一个......
  • C++函数编译原理和成员函数的实现
    对象的内存中只保留了成员变量,除此之外没有任何其他信息,程序运行时不知道stu的类型为Student,也不知道它还有四个成员函数setname()、setage()、setscore()、show(),C++......
  • C++多态性
    虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。虚函数    是在基类中使用关键字virtual声明的函数。在派生类中重......
  • C++数据结构和算法:位运算、字符串
    --------------------------------位运算---------------------------------Q1.用位运算交换两个值前提:要交换的两个值是独立内存voidSwap(int&a,int&b){a......
  • KubeSphere 多行日志采集方案深度探索
    作者:大飞哥,视源电子运维工程师,KubeSphere用户委员会广州站站长采集落盘日志日志采集,通常使用EFK架构,即​​ElasticSearch​​,​​Filebeat​​,​​Kibana​​,这是在主......
  • KubeSphere 多行日志采集方案深度探索 
    作者:大飞哥,视源电子运维工程师,KubeSphere用户委员会广州站站长采集落盘日志日志采集,通常使用EFK架构,即ElasticSearch,Filebeat,Kibana,这是在主机日志采集上非常成......
  • C++——多层嵌套模板类的静态成员变量的声明与定义方式
    在C++类的设计中,静态成员变量必须在类中声明,在类外定义,对于模板类亦是如此。如果只是单层级的模板类,其声明方式参考如下代码:template<typenameupid_t>classparent......
  • C++小蜜蜂
    #include<iostream>#include<string>#include"minecraft.h"usingnamespacestd;TxMinecraftmc;voidbol(intx,inty,intz);voidemo(intx,inty,intz);voidwine......
  • C++如何做字符串分割(5种方法)
    C++如何做字符串分割(5种方法)卧_听风雨于 2021-04-0617:54:50 发布55916 收藏 163分类专栏: C++ 文章标签: C++ 字符串分割版权C++专栏收录该内......