| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1392 人关注过本帖
标题:[求助]我很笨,求助一个简单的题目!
只看楼主 加入收藏
Antigloss
Rank: 1
等 级:新手上路
帖 子:109
专家分:0
注 册:2004-12-30
收藏
得分:0 
以下是引用当当在2005-5-21 11:30:57的发言: HourlyWorker(const char *n, double w, double h) : Employee(n) { wage = w, hours = h; } HourlyWorker(char* q, double a, double b) : Employee(q), wage(a), hours(b) {} 能够告诉我这两种调用的方法的区别在哪里啊,意义有什么不同,上面一种能够理解,但是下面的方法有点不能理解了。

想知道就去看《深度探索C++对象模型》作者:Stanley B. Lippman 以下解释引自《深度探索C++对象模型》第二章第四节

2.4 Member Initialization List

When you write a constructor, you have the option of initializing class members either through the member initialization list or within the body of the constructor. Except in four cases, which one you choose is not significant.

In this section, I first clarify when use of the initialization list is "significant" and then explain what actually gets done with that list internally. I then look at a number of possible, subtle pitfalls.

You must use the member initialization list in the following cases in order for your program to compile:

  1. When initializing a reference member

  2. When initializing a const member

  3. When invoking a base or member class constructor with a set of arguments

In the fourth case, the program compiles and executes correctly. But it does so inefficiently. For example, given

class Word { 
   String _name; 
   int _cnt; 
public: 
   // not wrong, just naive ... 
   Word() { 
      _name = 0; 
      _cnt = 0; 
   } 
}; 

this implementation of the Word constructor initializes _name once, then overrides the initialization with an assignment, resulting in the creation and the destruction of a temporary String object. Was this intentional? Unlikely. Does the compiler generate a warning? I'm not aware of any that does. Here is the likely internal augmentation of this constructor:

// Pseudo C++ Code 
Word::Word( /* this pointer goes here */ ) 
{ 
   // invoke default String constructor 
   _name.String::String(); 

   // generate temporary 
   String temp = String( 0 ); 

   // memberwise copy _name 
   _name.String::operator=( temp ); 

   // destroy temporary 
   temp.String::~String(); 

   _cnt = 0; 
} 

Had the code been reviewed by the project and corrected, a significantly more efficient implementation would have been coded:

// preferred implementation 
Word::Word : _name( 0 ) 
{ 
   _cnt = 0; 
} 

This expands to something like this:

// Pseudo C++ Code 
Word::Word( /* this pointer goes here */ ) 
{ 
   // invoke String( int ) constructor 
   _name.String::String( 0 ); 
   _cnt = 0; 
} 

This pitfall, by the way, is most likely to occur in template code of this form:

template < class type > 
foo< type >::foo( type t ) 
{ 
   // may or may not be a good idea 
   // depending on the actual type of type 
   _t = t; 
} 

This has led some programmers to insist rather aggressively that all member initialization be done within the member initialization list, even the initialization of a well-behaved member such as _cnt:

// some insist on this coding style 
Word::Word() 
   : _cnt( 0 ), _name( 0 ) 
   {} 

A reasonable question to ask at this point is, what actually happens to the member initialization list? Many people new to C++ confuse syntax of the list with that of a set of function calls, which of course it is not.

The compiler iterates over the initialization list, inserting the initializations in the proper order within the constructor prior to any explicit user code. For example, the previous Word constructor is expanded as follows:

// Pseudo C++ Code 
Word::Word( /* this pointer goes here */ ) 
{ 
   _name.String::String( 0 ); 
   _cnt = 0; 
}+ 

Hmm-m-m. It looks exactly the same as when _cnt was assigned within the body of the constructor. Actually, there is a subtlety to note here: The order in which the list entries are set down is determined by the declaration order of the members within the class declaration, not the order within the initialization list. In this case, _name is declared before _cnt in Word and so is placed first.

This apparent anomaly between initialization order and order within the initialization list can lead to the following nasty pitfall:

class X { 
   int i; 
   int j; 
public: 
   // oops!  do you see the problem? 
   X( int val ) 
      : j( val ), i( j ) 
      {} 
   ... 
}; 

The difficulty with this bug is how difficult it is even to see it. Compilers should issue a warning, yet there is only one that I am aware of that does (g++, the GNU C++ compiler). [6] I recommend always placing the initialization of one member with another (if you really feel it is necessary) within the body of the constructor, as follows:

[6] Unfortunately, the person who wrote telling me of the warning's generation also told me that his group had never actually understood what the warning's warning was about until he had read the above few paragraphs in a column I wrote for the C++ Report.

// preferred idiom 
X::X( int val ) 
   : j( val ) 
{ 
   i = j; 
} 

Here is an interesting question: Are the entries in the initialization list entered such that the declaration order of the class is preserved? That is, given

// An interesting question is asked: 
X::X( int val ) 
   : j( val ) 
{ 
   i = j; 
} 

is the initialization of j inserted before or after the explicit user assignment of j to i? If the declaration order is preserved, this code fails badly. The code is correct, however, because the initialization list entries are placed before explicit user code.

Another common question is whether you can invoke a member function to initialize a member, such as

// is the invocation of X::xfoo() ok? 
X::X( int val ) 
   : i( xfoo( val )), 
     j( val ) 
   {} 

where xfoo() is a member function of X. The answer is yes, but…. To answer the "but" first, I reiterate my advice to initialize one member with another inside the constructor body, not in the member initialization list. You don't know the dependencies xfoo() has regarding the state of the X object to which it is bound. By placing xfoo() within the constructor body, you can ensure there is no ambiguity about which members are initialized at the point of its invocation.

The use of the member function is valid (apart from the issue of whether the members it accesses have been initialized). This is because the this pointer associated with the object being constructed is well formed and the expansion simply takes a form like the following:

// Pseudo C++ Code: constructor augmentation 
X::X( /* this pointer, */ int val ) 
{ 
   i = this->xfoo( val ); 
   j = val; 
} 

Finally, then, what about this, in which a derived class member function is invoked to pass an argument to the base class constructor:

// is the invocation of FooBar::fval() ok? 
class FooBar : public X { 
   int _fval; 
public: 
   int fval() { return _fval; } 
   FooBar( int val ) 
      : _fval( val ), 
        X( fval() ) 
      {} 
   ... 
}; 

What do you think? A good idea or not? Here is its probable expansion:

// Pseudo C++ Code 
FooBar::FooBar( /* this pointer goes here */ ) 
{ 
   // Oops: definitely not a good idea 

   X::X( this, this->fval() ); 
   _fval = val; 
}; 

It's definitely not a good idea. (In later chapters, base and virtual base class initialization within the member initialization list is detailed.)

In summary, the compiler iterates over and possibly reorders the initialization list to reflect the declaration order of the members. It inserts the code within the body of the constructor prior to any explicit user code.

2005-05-21 12:48
Antigloss
Rank: 1
等 级:新手上路
帖 子:109
专家分:0
注 册:2004-12-30
收藏
得分:0 
以下是引用zsh0435在2005-5-21 12:10:37的发言:

两种方法没有什么区别,只不过第一个形参里的char *n是常指针。初始化后就不能再指向其它地址了!

const char *是一个指向const char的指针。初始化后仍可以指向别的地址。 必须用const char *才能指向const char。 但是const char *也可以指向char。 char *不能指向const char。 初始化后不能指向别的地址的定义形式为: char a; char * const n = &a; 因为看的是英文版,实在不知道某些名词中文怎么翻译,所以直接用c++的语法来表达。大家将就着看吧。如果有心看的话。

[此贴子已经被作者于2005-5-21 13:07:50编辑过]

2005-05-21 12:56
zsh0435
Rank: 1
等 级:新手上路
帖 子:23
专家分:0
注 册:2005-5-21
收藏
得分:0 
好像正如楼上兄台所说
抱歉,大概是我记错了

人生就是一个程序! 人降生到这个世间就是主函数的开始。 我们生活中的每个部分都是程序中的一段代码。 在调用不同的函数。
2005-05-21 13:05
快速回复:[求助]我很笨,求助一个简单的题目!
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.012744 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved