使用“:”符号在C ++中定义构造函数 [英] Use of ":" symbol to define a constructor in C++

查看:147
本文介绍了使用“:”符号在C ++中定义构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从结构C转移到OOP C ++,我经常发现在C ++中声明/定义构造函数时,使用符号作为运算符。我大致理解这种风格的使用,但有人用这个构造函数定义解释我的确切的编程技术。



例如:1

  class time_stamp 
{
public:
time_stamp(time& t_time)
:m_time(t_time)
{}

〜time_stamp()
{
m_time.update(); //一旦我被销毁,更新时间
}
private:
time& m_time;
};

例如:2

  class threaded_class 
{
public:
threaded_class()
:m_stoprequested(false),m_running(false)
{
pthread_mutex_init (& m_mutex);
}

〜threaded_class()
{
pthread_mutex_destroy(& m_mutex);
}

/ **其他成员声明* /

}

请解释我在上面的代码中使用2个例子
time_stamp(time& t_time):m_time(t_time){}

  threaded_class m_stoprequested(false),m_running(false)
{
pthread_mutex_init(& m_mutex);
}


解决方案

冒号用于表示构造函数成员初始化器列表。这是您可以启动类成员或调用基类构造函数的地方。



C ++标准n3337 12.6.2 § 3:


mem-initializer-list可以使用任何
类或者声明类型初始化一个基类, 。


C ++标准n3337 12.6.2 § 7:


在mem初始化器中的表达式列表或支撑初始化列表用于
初始化指定的子对象(或者在
的情况下委托构造函数,完整的类对象)根据用于直接初始化的
初始化规则。


示例: / p>

  class Foo {
int a;
};

如果您希望整型 a 在调用构造函数之后,你必须在构造函数中给出 a 这个值。在构造函数体中有两个选项:






  •   Foo :: Foo(){
    a = 70;
    }


  • 是它的成员初始化列表

      Foo :: Foo():a(70){
    }




应首选通过成员初始化列表初始化



总是合法,永远不会低于构造函数体内的赋值效率,并且通常更有效。关于初始化列表的重要事情是允许直接初始化类成员省略一个成员的默认构造受到这样的过程。



As Scott Myers在他的Effective C ++中指出,如果你没有为类成员指定一个初始化参数,它的默认构造函数将被调用。当你以后在类构造函数中执行赋值时,你将在成员变量中调用 operator = 。这将总共两次调用成员函数:一个用于默认构造函数,另一个用于赋值。您可以通过指定初始化程序来忽略第一个调用。同样,Scott Myers在他的Effective C ++中指出:从纯粹务实的角度来看,有时候必须使用初始化列表,特别是 const 并且引用成员只能被初始化,从不分配。



陷阱



(至少)同样重要的是,成员不会按照外观在初始化列表中,但按类中的声明顺序。记住这样可以避免类似于

  / *尝试分配非常大的内存块
的错误,向量与
未初始化的整数:std :: vector< int> v(N)
* /
class SearchEngine {
std :: vector< int> v;
int N;
explicit SearchEngine(std :: vector< int> const& keys)
:N(keys.size()),v(N),{
/ pre>

C ++标准n3337 8.5.4 § 1:


列表初始化是来自
braced-init-list的对象或引用的初始化。这样的初始化程序称为初始化程序列表
和列表的逗号分隔的初始化子句称为初始化程序列表的
元素。初始化程序列表可能为空。
列表初始化可以发生在direct-initialization或copy-
初始化上下文中;
直接初始化上下文中的列表初始化称为直接列表初始化,而
list-initialization在复制初始化上下文中称为
copy-list-initialization。 [注意:可以使用列表初始化作为
变量定义(8.5)中的初始化器



- 作为
a中的初始化器new表达式(5.3.4)



- 作为
function argument(5.2.2)



作为下标(5.2.1)




a构造函数调用的参数(8.5,5.2.3)



- 作为
非静态数据成员的初始化器(9.2) / p>

- 在mem初始化程序(12.6.2)中

- 在
右侧(5.17)



[示例:



int a = {1}



std :: complex z {1,2};



new std :: vector {once,
upon,a,time}; // 4个字符串元素



f({Nicholas,Annemarie}
); //传递两个元素的列表



return {Norah}; // return list of
one element



int * e {}; //初始化为零/空指针



x =
double {1}; //显式构造一个double



std :: map
anim = {{bear,4},{cassowary,2} tiger,7}};



- end example] - end note]



I am moving from structural C to OOP C++ and I frequently found a special use of ":" symbol as an operator when declaring/defining constructors in C++. I roughly understood the use of this style but somebody explain me the exact programming technique with this constructor definition.

e.g.: 1

class time_stamp
{
public:
    time_stamp(time &t_time)
        : m_time(t_time)
    {}

    ~time_stamp()
    {
        m_time.update(); // as soon as I'm destroyed, update the time
    }
private:
    time &m_time;
};

e.g.: 2

class threaded_class
{
public:
    threaded_class()
        : m_stoprequested(false), m_running(false)
    {
        pthread_mutex_init(&m_mutex);
    }

    ~threaded_class()
    {
        pthread_mutex_destroy(&m_mutex);
    }

    /** Some other member declarations */

}

Please explain me use of ":" in below lines of codes from above 2 examples time_stamp(time &t_time) : m_time(t_time){} and

threaded_class(): m_stoprequested(false), m_running(false)
{
   pthread_mutex_init(&m_mutex);
}

解决方案

The colon character : is used to denote the constructor member initializer list. This is the place where you can initiailze members of a class or call a base class constructor.

C++ Standard n3337 12.6.2 § 3:

A mem-initializer-list can initialize a base class using any class-or-decltype that denotes that base class type.

C++ Standard n3337 12.6.2 § 7:

The expression-list or braced-init-list in a mem-initializer is used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of 8.5 for direct-initialization.

Example:

class Foo {
   int a;
};

If you would like integer a to have determined value after call to constructor is made you have to give a this value in constructor. There are two options:

  • in constructor body

    Foo::Foo() {
        a = 70;
    }
    

  • in it's member initializer list

    Foo::Foo() : a( 70) {
    }
    

Initialization via a member initilization list should be preferred

It is always legal, is never less efficient than assignment inside the body of the constructor, and is often more efficient. The very important thing about initialization list is that it allows to direct initialize class member omitting a default construction of a member being subject to such a process.

As Scott Myers pointed out in his "Effective C++", if you fail to specify an initialization argument for class member, it's default constructor will be called. When you later perform an assignment to it inside your class constructor, you will call operator= on member variable. That will total two calls to member functions: one for the default constructor and one more for the assignment. You can omit a first call by specifying an initializer. Also as Scott Myers pointed out in his "Effective C++" : "from a purely pragmatic point of view, there are times when the initialization list must be used. In particular, const and reference members may only be initialized, never assigned".

A trap

(At least) Equally important thing is that members are not initialized in order of their appearance in initialization list but in order of declaration in class. Remember this to avoid errors like

/* trying to allocate very large block of memory
   as a result of initializing a vector with
   uninitialized integer: std::vector<int> v( N)
*/
class SearchEngine {
    std::vector<int> v;
    int N;
    explicit SearchEngine( std::vector<int> const& keys)
                  : N( keys.size()), v( N), {

C++ Standard n3337 8.5.4 § 1:

List-initialization is initialization of an object or reference from a braced-init-list. Such an initializer is called an initializer list, and the comma-separated initializer-clauses of the list are called the elements of the initializer list. An initializer list may be empty. List-initialization can occur in direct-initialization or copy- initialization contexts; list-initialization in a direct-initialization context is called direct-list-initialization and list-initialization in a copy-initialization context is called copy-list-initialization. [ Note: List-initialization can be used — as the initializer in a variable definition (8.5)

— as the initializer in a new expression (5.3.4)

— in a return statement (6.6.3)

— as a function argument (5.2.2)

— as a subscript (5.2.1)

— as an argument to a constructor invocation (8.5, 5.2.3)

— as an initializer for a non-static data member (9.2)

— in a mem-initializer (12.6.2)

— on the right-hand side of an assignment (5.17)

[ Example:

int a = {1};

std::complex z{1,2};

new std::vector{"once", "upon", "a", "time"}; // 4 string elements

f( {"Nicholas","Annemarie"} ); // pass list of two elements

return { "Norah" }; // return list of one element

int* e {}; // initialization to zero / null pointer

x = double{1}; // explicitly construct a double

std::map anim = { {"bear",4}, {"cassowary",2}, {"tiger",7} };

— end example ] — end note ]

这篇关于使用“:”符号在C ++中定义构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆