c++基础语法:构造函数初始化列表_C 语言

C++为类中提供类成员的初始化列表

类对象的构造 顺序是这样的:
1.分配内存,调用构造函数 时,隐式/显示的初始化各数据 成员
2.进入构造函数后在构造函数中执行一般计算

使用初始化列表有两个原因:

1.必须这样做:
如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,如果没有初始化列表,那么他将无法完成第一步,就会报错。

复制代码 代码如下:

class  ABC
  ... {
 public :
          ABC( int  x, int  y, int  z);
 private :
           int  a;
           int  b;
           int  c;
 } ;
 class  MyClass
  ... {
 public :
          MyClass():abc( 1 , 2 , 3 ) ... {}
 private :
         ABC abc;
 } ;

因为ABC有了显示的带参数的构造函数,那么他是无法依靠编译器生成无参构造函数的,所以没有三个int型数据,就无法创建ABC的对象。

ABC类对象是MyClass的成员,想要初始化这个对象abc,那就只能用成员初始化列表,没有其他办法将参数传递给ABC类构造函数。

另一种情况是这样的:当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。

2.效率要求这样做:
类对象的构造顺序显示,进入构造函数体后,进行的是计算,是对他们的赋值操作,显然,赋值和初始化是不同的,这样就体现出了效率差异,如果不用成员初始化类表,那么类对自己的类成员分别进行的是一次隐式的默认构造函数的调用,和一次复制操作符的调用,如果是类对象,这样做效率就得不到保障。

注意:构造函数需要初始化的数据成员,不论是否显示的出现在构造函数的成员初始化列表中,都会在该处完成初始化,并且初始化的顺序和其在声明时的顺序是一致的,与列表的先后顺序无关 ,所以要特别注意,保证两者顺序一致才能真正保证其效率。

为了说明清楚,假设有这样一个类:

复制代码 代码如下:

class foo{
   private :
    int a, b;
};

1、foo(){}和foo(int i = 0){}都被认为是默认构造函数,因为后者是默认参数。两者不能同时出现。

2、构造函数列表的初始化方式不是按照列表的的顺序,而是按照变量声明的顺序。比如foo里面,a在b之前,那么会先构造a再构造b。所以无论 foo():a(b + 1), b(2){}还是foo():b(2),a(b+1){}都不会让a得到期望的值。如果先声明b再声明a则会更好。

3、构造函数列表能够对const成员初始化。比如foo里面有一个int const c;则foo(int x) : c(x){}可以让c值赋成x。不过需要注意的是,c必须在每个构造函数(如果有多个)都有值。

4、在继承里面,只有初始化列表可以构造父类的private成员。比如说

复制代码 代码如下:

class child : public foo{
}

foo里面的构造函数是这样写的:foo (int x) { a = x; }.
而在child里面写child(int x){ foo(x); }是通过不了编译的。只有把父类初始化改为foo(int x) : a(x){}而子类构造写作child (int x) : foo(x){}才可以。

C++ 初始化类的成员,不但可以用构造函数(constructor)完成,而且可以用初始化类成员列表来完成。MFC大量用到此方法。例如有些初学者可能不大理解如下代码:
class A
{
  public:
    int member_var; //成员变量
    A();            //构造函数
}
A::A():member_var(0)
{
}

他们觉得这个构造函数的定义应该只能这样写:
A::A()
{
   member_var=1;
}
其实两种方法都可。但是有些情况下,只能用第一种,而且通常情况下用第一种也会效率高些。

其实,第一种方法是真正的初始化(initialization ),而在构造函数内实现的“=”操作其实是赋值(assign)。这两种方法的一切区别从这儿开始。区别大概如下:

1.我们知道普通变量编译器都会默认的替你初始化。他们既能初始化,也能被赋值的,而常量(const)按照其意思只能被初始化,不能赋值。否则与变量就无区别了。所以常量成员(const member)只能用成员初始化列表来完成他们的“初始化”,而不能在构造函数内为他们“赋值”。

2.我们知道类的对象的初始化其实就是调用他的构造函数完成,如果没有写构造函数,编译器会为你默认生成一个。如果你自定义了带参数的构造函数,那么编译器将不生成默认构造函数。这样这个类的对象的初始化必须有参数。如果这样的类的对象来做另外某个类的成员,那么为了初始化这个成员,你必须为这个类的对象的构造函数传递一个参数。同样,如果你在包含它的这个类的构造函数里用“=”,其实是为这个对象“赋值”而非“初始化”它。所以一个类里的所有构造函数都是有参数的,那么这样的类如果做为别的类的成员变量,你必须显式的初始化它,你也是只能通过成员初始化列表来完成初始化。 例如:

复制代码 代码如下:

class B
{
......
}

class A
{
  public:
  B member_b;
  A();
}
A::A():B(...) //你必须显式初始化它,因为他的所有构造函数
              //都是有参数的,之后才能被赋值。
{
  B=...; //因为如上所写,已经初始化了,才能被赋值,否则错误。
}

初始化顺序:

复制代码 代码如下:

class test

{

       const int a;

       std:string str;

       object o;

       test():str(“df”),o(null) ,a(0)

{

}    

};

黄色的既是初始化列表,他们会在构造函数正式调用前被调用,且他们的初始化顺序并不是根据 初始化列表中出现的顺序,而是他们声明的顺序来初始化。如上:

初始化顺序是: a, str, o;

一般用于初始化 常量类型,静态类型的数据,或者不能独立存在的数据

时间: 2024-09-05 16:23:38

c++基础语法:构造函数初始化列表_C 语言的相关文章

c++基础语法:构造函数与析构函数_C 语言

说实话c++还是以前在学校的时候用过的,从毕业到现在一直用c嵌入式编程,现在重新搬出C++语法 ,如果理解上有错误的地方,还请路过的朋友多指正--- 构造函数用来构造一个对象,主要完成一些初始化工作,如果类中不提供构造函数,编译器会默认的提供一个默认构造函数(参数为空的构造函数就是默认构造函数) :析构函数是隐式调用的,delete对象时候会自动调用完成对象的清理工作. 现在主要看看继承中的构造函数和析构函数的调用: 复制代码 代码如下: class  A {} :class  B : publ

c++ 构造函数的初始化列表_C 语言

首先,运行下图中的C++代码,输出是什么? 复制代码 代码如下: class A{private: int n1; int n2;public: A(): n2(0) , n1(n2 + 2) { } void Print() {  cout<<"n1:"<<n1<<",n2:"<<n2<<endl; }};int main(void){ A a; a.Print(); return 0;} 答案:输出n1

C++构造函数深度学习_C 语言

本文针对C++构造函数进行深度探究,供大家参考,具体内容如下 1.引子:  以下代码中的输出语句输出0吗,为什么? struct Test { int _a; Test(int a) : _a(a) {} Test() { Test(0); } }; Test obj; cout << obj._a << endl; 输出为:-858993460 2.剖析上面代码的输出为一个垃圾值,也就是说obj调用构造函数并没有对成员进行初始化工作,虽然默认无参构造Test()内部调用了Test

c++-C++类构造函数初始化列表

问题描述 C++类构造函数初始化列表 #include using namespace std; class A { private: int n1; int n2; public: A() { n2=0; n1=n2+2; }//输出结果为:n1:2, n2: 0 A():n2(0),n1(n2+2){}//输出结果为n1:-858993458, n2: 0 //上面这两种方式有啥区别,求指导,为啥结果不一样 void Print(){ cout << "n1:" <

C语言中结构体(struct)的几种初始化方法_C 语言

本文给大家总结的struct数据有3种初始化方法      1.顺序      2.C风格的乱序      3.C++风格的乱序 下面通过示例代码详细介绍这三种初始化方法. 1)顺序 这种方法很常见,在一般的介绍C的书中都有介绍.顺序初始化的特点是: 按照成员定义的顺序,从前到后逐个初始化:允许只初始化部分成员:在被初始化的成员之前,不能有未初始化的成员. 示例: struct User oneUser = {10, "Lucy", "/home/Lucy"}; 2

解析C++中构造函数的默认参数和构造函数的重载_C 语言

C++构造函数的默认参数 和普通函数一样,构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值. [例] #include <iostream> using namespace std; class Box { public : Box(int h=10,int w=10,int len=10); //在声明构造函数时指定默认参数 int volume( ); private : int height; int width; int l

c++获取进程信息列表和进程所调用的dll列表_C 语言

复制代码 代码如下: // -----------------------// FileName: // ProcessInfo.h// remarks:// 基于应用层实现,有的进程,如杀软进程等获取不到调用的dll列表.// ----------------------- #pragma once#include <vector> struct ProInfo{    // 保存进程PID    unsigned int uPID;    // 保存进程名    CString strPr

c++类构造函数详解_C 语言

复制代码 代码如下: //一. 构造函数是干什么的 /*   类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数->由构造函数完成成员的初始化工作     eg: Counter c1;      编译系统为对象c1的每个数据成员(m_value)分配内存空间,并调用构造函数Counter( )自动地初始化对象,初始化之后c1的m_value值设置为0      故:构造函数的作用:初始化对象的数据成员.*/       class Counter       {      publ

C++友元函数与拷贝构造函数详解_C 语言

一.友元函数 1.友元函数概述: (1)友元函数是定义在一个类外的普通函数. 友元函数和普通函数的定义一样;在类内必须将该普通函数声明为友元. (2)友元函数不是成员函数. 不能通过对象来调用,而是直接调用;友元函数可以访问类的公有.受保护以及私有成员,但是必须通过对象.对象指针或者对象引用来访问. 2.友元函数的声明: friend 返回值类型 函数名(参数表); 在类中只需要将这个声明放置在公有部分即可. class Point { double x, y; public: Point(){