C++构造函数 初始化列表 的神秘之处

首先了解类对象的构造顺序是怎样的:

1.分配内存,调用构造函数时,隐式/显式的初始化个数据成员

(构造函数列表的初始化方式不是按照列表的顺序,而是按照变量声明的顺序同时初始化显隐    数据成员);

2.进入构造函数后在构造函数中执行一般赋值与计算。

使用初始化列表的原因:

 一:只能使用初始化列表

  1.初始化 const 修饰的类成员(常变量) 或 初始化引用成员数据;(因为这些变量初始化时必须赋值)

  2.子类初始化父类的私有成员

  3.数据成员是对象,并且这个对象只有含参数的构造函数,没有无参数的构造函数;

针对三进行说明:

class Test {
public:
    Test() {};
    Test(int x) { int_x = x;
    std::cout << int_x << std::endl;
    };
    void show() { std::cout << int_x << std::endl; }
private:
    int int_x;
};
class Mytest :public Test {
public:
    Mytest():Test(110) 
    {
        //Test(110);            //  构造函数只能在初始化列表中被显示调用,不能在构造函数内部被显示调用
    };
};
int _tmain(int argc, _TCHAR* argv[])
{
    Test *p = new Mytest();
    p->show();
    return 0;
}

结果:如果在构造函数内部被显示调用输出结果是:-842150451(原因是虽然调用了 Test (int x),但是直接调用构造函数产生了一个临时对象,而不是调用父类的构造函数来构造父类的私有变量,作用域只在一条语句中,所以相当于什么都没做。故而直接打印出一个随机值。)

二:效率问题

  ①:如果在类的构造函数里面进行赋值:在成员初始化时会调用一次其默认的构造函数,在类构造函数里又会调用一次成员的构造函数再赋值。

  ②:如果在类构造函数使用初始化列表:仅在初始化列表里调用一次成员的构造函数并且赋值

template<class T>
class My
{
    public:
        My()
        {
            //使用了赋值操作符 operator=(LPCTSTR);
            m_str = T("hello");
        }

        My()//使用类成员列表
        :my_str(T("hello"))
{}
    private:
        T* m_str;
};

  分析:编译期总是确保所有的成员对象在构造函数体执行之前初始化,因此在第一个例子中编译的代码将调用CString::CString来初始化my_str,这是在控               制到达赋值语句之前完成。在第二个例子中,编译器产生一个对CString::CString(LPCTSTR)的调用并将“hello”传递给这个函数。

            产生的结果就是:在第一个例子中调用了两次CString函数(构造函数和赋值操作),而在第二个例子中只调用了一次函数。

            不过在CString的例子里这是无所谓的,因为缺省构造函数是内联的,CString只是在需要时为字符串分配内存(当你实际赋值时)。但是一般而言,     重复函数是浪费资源的,尤其是在构造函数和赋值操作符非配内存的时候。

构造函数:

  首先,在程序定义变量并初始化的机制中,有两种形式:①传统的初始化-通过赋值运算符初始化②另外一种就是括号赋值。

int a = 10;
char c ='a';


//括号赋值运算

int a(10);
char c('a');

上述初始化是可以的,但他们的唯一不同是:括号运算符进行赋值时只能在初始化时,而等号则可以先定义在赋值。

int a;
a =10;

int a;
a(10);
//编译器会认为这是一个函数:函数名为a参数为10;

1. 构造函数的作用是:创建一个类的对象时,调用它的构造函数来构造这个类对象的数据成员,①给数据成员分配内存空间②是要给函数数据成员初始化(这个顺序是按照数据成员在类中的申明的顺序进行构造)。

冒号初始化数据成员 和 构造函数内初始化的区别
冒号初始化: 给数据成员分配内存空间时就进行了初始化(必须是括号赋值),也就是在分配了内存空间后在进入函数体之前就给数据成员赋值了,也就是初始化这个数据成员时函数体还没执行。
构造函数内初始化:

是在所有数据成员分配空间之后,进入函数体之后才进行赋值的。这样也是有好处的

:有的数据成员需要在构造函数调用之后函数体执行之前进行初始化 如 引用,常量

  


private:

	const int i;//这里也可以直接完成初始化,const  int  i=100,不报错,但是去变量意义

	int p;

	int &j=p;

};

猜你喜欢

转载自blog.csdn.net/genzld/article/details/86438888