C++类的成员初始化列表的相关问题

在以下四中情况下,要想让程序顺利编译,必须使用成员初始化列表(member initialization list):

  1,初始化一个引用成员(reference member);

  2,初始化一个常量对象(const member);

  3,调用一个基类的构造函数,且该基类的构造函数有一组参数;

  4,调用一个成员类(member class)的构造函数,且该构造函数有一组参数

  这四种情况程序可以正常编译,但是效率有所欠缺(下面会具体说到)。

  class Word{

    String _name;

    int   _cnt;

  public:

    Word()  {

    _name = 0;

    _cnt = 0;

    }

  };

  上面这个程序的实现机制是:Word类的构造函数会先生成一个String类的临时对象(注意,_name是String类的对象),然后对该临时对象初始化。

然后通过赋值运算符将临时对象赋给_name,最后析构该临时对象。

  以下是构造函数的内部扩张结果,c++伪代码:

  Word::Word()

  {

  _name.String::String();   //调用String类的默认构造函数(default constructor)

  String temp = String(0);  //产生类的临时对象 并初始化

  _name.String::operator = (temp);  //通过赋值运算符将临时对象的值(深)拷贝给 _name

  temp.String::~String();     //调用String的析构函数

  _cnt = 0;

  }

  以上的代码效率并不高,因为中间需要调用默认构造函数和析构函数生成和销毁一个临时对象,以下是一个更有效率的实现方法:

  Word::Word : _name (0)   //_name直接调用String类的构造函数对其赋值

  {

    _cnt = 0;

  }

  它会被构造函数扩张成以下的形式(c++伪代码)

  Word::Word()

  {

    _name.Sting::String(0);    //调用String (int) 构造函数

    _cnt = 0;

  }

  成员初始化列表并不是一组函数调用,编译器一一操作初始化列表,以适当的顺序在构造函数中插入初始化的操作,并且是在程序员显式的写入代码之前进行。

列表的中的项目次序是由类中的成员声明次序决定的,不是由初始化列表中的排列顺序决定。“初始化次序”和“初始化列表中的项目排列顺序”的错乱会带来意想不到的错误:

  class X {

    int i;

    int j;

  public:

    X (int value) : j (value), i (j)

   {}....

  }; 以上代码编写者的本意是要把j的初值设置为 value, 再把 i 的初值设置为 j 。然而,由于声明次序 i 在 j 之前,初始化列表中 i(j) 实际上比 j(value)更早执行,

这就带来了意想不到的错误。正确的写法应该是:

 class X {

    int i;

    int j;

  public:

    X (int value) : j (value)       // j (value) 此处调用构造函数赋初值

    { i = j; }

  };

  虽然这种写法仍然是 i 声明在 j 之前,但是并不会发生错误,因为初始化列表中的项目被插入到构造函数中不会再保持原来的声明次序,也就是说初始化列表被插入到构造函数中初始化列表中的项目顺序优先级高于代码编写者显式声明的顺序。

时间: 2024-10-03 10:02:09

C++类的成员初始化列表的相关问题的相关文章

c++类 用冒号初始化对象(成员初始化列表)

c++类 用冒号初始化对象(成员初始化列表) 成员初始化的顺序不同于它们在构造函数初始化列表中的顺序,而与它们在类定义中的顺序相同 #include<iostream> int n=0; using namespace std; class Cbox{ int a ; int b ; int c ; public: int g ; Cbox():a(n++),c(n++),b(n++){} ~Cbox(){cout<<a<<" "<<b&

C++对象模型——成员初始化列表(第二章)

2.4    成员初始化列表 (Member Initialization List) 当编写一个类的构造函数时,有可能设定类成员的初始值,或者通过成员初始化列表初始化,或者在构造函数内初始化,除了四种情况,其实任何选择都差不多. 本节中,首先澄清何时使用初始化列表才有意义,然后解释初始化列表内部的真正操作是什么,然后再看一些微妙的陷阱.  下列情况中,为了让程序能够被顺利编译,必须使用成员初始化列表(不能在构造函数内初始化): 1.    当初始化一个引用的成员时 2.    当初始化一个常量

【C/C++】构造函数、默认构造函数、成员初始化列表

常见问题 Q1. 下列关于构造函数的描述中,错误的是( ) A. 构造函数可以设置默认的参数 B. 构造函数在定义类对象时自动执行 C. 构造函数可以是内联函数 D. 构造函数不可以重载 Q2. 下列代码中a.b的各个成员变量值是多少? 1 class Student 2 { 3 public: 4 Student() {} 5 void show(); 6 private: 7 string name; 8 int number; 9 int score; 10 }; 11 Student a

C++ 初始化形式、变量初始化规则、类构造函数的初始化列表

类构造函数的初始化列表,举例 一个对象的构造分两部分,首先是分配空间,然后初始化. 只要有对象生成,不管是以什么形式生成,都会调用构造函数进行初始化. 然后下面有个例子,在蓝色区域Big类的复制构造函数中,使用初始化列表进行成员的初始化(方法1)没有问题,而如果不使用初始化列表.直接在函数里用里面注释掉的代码(方法2)则会报错:Base类没有合适的构造函数. // W3-课程作业2-4.cpp : Defines the entry point for the console applicati

C++:用成员初始化列表对数据成员初始化

1.在声明类时,对数据成员的初始化工作一般在构造函数中用赋值语句进行. 例如: class Complex{ private: double real; double imag; public: Complex(double r,double i) //声明构造函数原型 { ........... } }; Complex::Complex(double r,double i) //在构造函数中用赋值语句对数据成员赋初值 { real = r; imag = i; } 2.另一种初始化数据成员的

C++成员初始化列表

class A { public: A() { cout << "class A default constructor called" << endl; a = 0; } A(int param) { cout << "class A constructor called" << endl; a = param; } ~A() { } virtual void FunctionA() { cout <<

成员初始化列表的使用及特点

成员初始化列表:用于辅佐构造函数(可以是默认构造函数),对成员变量进行赋值. 一般情况下,使用成员初始化列表与在构造函数内部对成员进行赋值没有什么好坏之分,使用哪种方式对对象进行初始化全凭心情. 但是,在以下四种情况的成员变量中,只能使用成员初始化列表进行初始化: 1.当初始化一个const member时.这种情况不用多说,对于const变量的初始化只能使用初始化列表,而不能在constructor中进行赋值,不然违背成员变量const的性质. 2.当初始化一个reference member

Java 类中成员初始化顺序

Java 中的类成员 基本分为 静态成员, 实例变量  方法中特别的是静态方法和构造方法. 1.定义一个类 public class ClassLoaderTest { public int a ; public String b; private static int c; public  ClassLoaderTest(){ System.out.println("执行前:"+ a + "  "+ b); a = 10; b = "lisi"

C#类的成员初始化顺序

首先我们来看看引用类型的成员初始化过程 我们来看一个例子吧 class Program {     static void Main(string[] args)     {         DriveB d = new DriveB();     } } class BaseA {     static DisplayClass a = new DisplayClass("基类静态成员初始化"); DisplayClass BaseA_c = new DisplayClass(&qu