printf参数,little endian,初始化列表来初始化
2016-10-04 00:24
197 查看
1,假设在一个 32 位 little endian 的机器上运行下面的程序,结果是多少?
解析:
1,大端字节序:高位存储在低字节
小段字节序:低位存储在低字节
2,printf是一个库函数,C,C++中函数的参数是从右往左入栈的;
3,栈的生长方向是从高往低的
4,%d格式输出的是4个字节大小,而long long为8个字节
5,printf函数的原型是printf(const char*,…);第二个参数是任意个数目的参数,所以printf函数不是分个把参数入栈,而是一股脑全部压入堆栈,因此对于8字节的数据来说,堆栈中的数据是0001 0000
0002 0000 0003 0000,%d按四字节输出,因此,第一个%d输出1,第二个%d输出0,第三个%d输出2。
所以输出为:1,0,2
大端字节序存储的话:0000 0001 0000 0010 0000 0011
则构造函数中,成员变量一定要通过初始化列表来初始化的是:__。
解析:
构造函数的执行可以分成两个阶段,初始化阶段和计算阶段,初始化阶段先于计算阶段。
初始化阶段
所有类类型(class type)的成员都会在初始化阶段初始化,即使该成员没有出现在构造函数的初始化列表中。
计算阶段
一般用于执行构造函数体内的赋值操作,下面的代码定义两个结构体,其中Test1有构造函数,拷贝构造函数及赋值运算符,为的是方便查看结果。Test2是个测试类,它以Test1的对象为成员,我们看一下Test2的构造函数是怎么样执行的。
调用代码:
运行结果:
而这里:当我们将其Test2改变为这样之后就是:
同样的,调用代码:
运行结果:
由上面的测试可知,使用初始化列表少了一次调用默认构造函数的过程,这对于数据密集型的类来说,是非常高效的。同样看上面的例子,我们使用初始化列表来实现Test2的构造函数
使用同样的调用代码,输出结果如下:
构造函数初始化时必须采用初始化列表一共有三种情况,
1,需要初始化的数据成员是对象(继承时调用基类构造函数)
2,需要初始化const修饰的类成员 ,因为常量只能在初始化,不能赋值,所以必须放在初始化列表中;
3,需要初始化引用成员数据 ,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表中;
4,没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。
对于没有默认构造函数的类,我们看一个例子:
以上代码无法通过编译,因为Test2类中Test1 test1;需要调用默认的构造函数,但是Test1类没有无参的构造函数,但是由于Test1没有默认的构造函数,故而编译错误。正确的代码如下,使用初始化列表代替赋值操作。
因为static属于类并不属于具体的对象,所以 static成员是不允许在类内初始化的,那么static const 成员是不是在初始化列表中呢?
答案是NO
一是static属于类,它在未实例化的时候就已经存在了,而构造函数的初始化列表,只有在实例化的时候才执行。
二是static成员不属于对象。我们在调用构造函数自然是创建对象,一个跟对象没直接关系的成员要它做什么呢
初始化:从无到有,创建了新对象;如:string foo = “Hello World!”
赋值:没有创建新对象,而是对已有对象赋值。 如:string bar; bar = “Hello World!”
有时我们可以忽略数据成员初始化和赋值之间的差异,但并非总能这样。
如果成员是const或者是引用的话,必须将其初始化。类似的,当成员属于某种类类型且该类没有定义默认构造函数时,也必须将这个成员初始化
运行结果:
若将代码该成这样:
运行结果:
这里的i相当于未定义(因为先于j声明)。所以,一个好的习惯是,按照成员定义的顺序进行初始化。
但是,但是,但是:
此时的const变量属于具体的一个对象,如何在整个类中都恒定不变呢?
答案是利用枚举,举例:
枚举常量不会占据对象的存储空间,在编译时被全部求值
但是,它隐含的数据对象类型为整形,不能表示其他类型。
问题
如何定义在类中定义非整形常量?(待解决)
const成员函数
任何不修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时,不慎修改了数据成员,或调用了其他非const成员函数,编译器就会指出错误。
同一个类中,可以仅通过是否是const定义两个函数名字、参数、返回值完全相同的两个成员函数,例如:
输出
结论
同函数名、参数、返回值可以仅通过是否为const来定义为类的两个成员函数。在调用时,const对象调用const成员函数,非const对象调用非const成员函数。
问题 1:
不可以在const函数中改变成员变量的值,那么有没有办法改变?
答案是可以的,把成员变量声明为mutable类型。看程序:
结果:
问题2:
当类中只有const函数,非const对象是否可以调用const函数?
答案是可以的,程序:
结果:
但是:只有const函数时,非const对象不可以调用那个const函数(否则,类的数据变量就会发生变化)。
问题3:
当类中存在只有 是否为const 不同的两个函数时,const函数是否可以暂时调用那个非const函数?
答案是可以的。用const_cast将转化掉表达式的const性质
结果:
注意
单纯用类转化不行
报错:
问题4:返回类型是const是怎么回事?
const返回类型只有在修饰指针或引用是才有用。单凭const返回类型不可以重载。
解析:
1,大端字节序:高位存储在低字节
小段字节序:低位存储在低字节
2,printf是一个库函数,C,C++中函数的参数是从右往左入栈的;
3,栈的生长方向是从高往低的
4,%d格式输出的是4个字节大小,而long long为8个字节
5,printf函数的原型是printf(const char*,…);第二个参数是任意个数目的参数,所以printf函数不是分个把参数入栈,而是一股脑全部压入堆栈,因此对于8字节的数据来说,堆栈中的数据是0001 0000
0002 0000 0003 0000,%d按四字节输出,因此,第一个%d输出1,第二个%d输出0,第三个%d输出2。
所以输出为:1,0,2
大端字节序存储的话:0000 0001 0000 0010 0000 0011
二:初始化列表的问题
1,如下:有一类A,其数据成员如下:则构造函数中,成员变量一定要通过初始化列表来初始化的是:__。
解析:
什么是初始化列表啊???
1,与其他函数不同,构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段。(在C++中,struct和class的唯一区别是默认的访问性不同,而这里我们不考虑访问性的问题)class foo { string name ; int id ; foo(string s, int i):name(s), id(i){} ; // 初始化列表 };
构造函数的执行可以分成两个阶段,初始化阶段和计算阶段,初始化阶段先于计算阶段。
初始化阶段
所有类类型(class type)的成员都会在初始化阶段初始化,即使该成员没有出现在构造函数的初始化列表中。
计算阶段
一般用于执行构造函数体内的赋值操作,下面的代码定义两个结构体,其中Test1有构造函数,拷贝构造函数及赋值运算符,为的是方便查看结果。Test2是个测试类,它以Test1的对象为成员,我们看一下Test2的构造函数是怎么样执行的。
class Test1 { Test1() // 无参构造函数 { cout << "Construct Test1" << endl ; } Test1(const Test1& t1) // 拷贝构造函数 { cout << "Copy constructor for Test1" << endl ; this->a = t1.a ; } Test1& operator = (const Test1& t1) // 赋值运算符 { cout << "assignment for Test1" << endl ; this->a = t1.a ; return *this; } int a ; }; class Test2 { Test1 test1 ; Test2(Test1 &t1) { test1 = t1 ; } };
调用代码:
Test1 t1 ; Test2 t2(t1) ;
运行结果:
而这里:当我们将其Test2改变为这样之后就是:
class Test2 { Test1 test1 ; Test2(Test1 t1)//这里去除了引用了 { test1 = t1 ; } };
同样的,调用代码:
Test1 t1 ; Test2 t2(t1) ;
运行结果:
由上面的测试可知,使用初始化列表少了一次调用默认构造函数的过程,这对于数据密集型的类来说,是非常高效的。同样看上面的例子,我们使用初始化列表来实现Test2的构造函数
struct Test2 { Test1 test1 ; Test2(Test1 &t1):test1(t1){} }
使用同样的调用代码,输出结果如下:
构造函数初始化时必须采用初始化列表一共有三种情况,
1,需要初始化的数据成员是对象(继承时调用基类构造函数)
2,需要初始化const修饰的类成员 ,因为常量只能在初始化,不能赋值,所以必须放在初始化列表中;
3,需要初始化引用成员数据 ,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表中;
4,没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。
对于没有默认构造函数的类,我们看一个例子:
class Test1 { Test1(int a):i(a){} int i ; }; class Test2 { Test1 test1 ; Test2(Test1 &t1) { test1 = t1 ; } };
以上代码无法通过编译,因为Test2类中Test1 test1;需要调用默认的构造函数,但是Test1类没有无参的构造函数,但是由于Test1没有默认的构造函数,故而编译错误。正确的代码如下,使用初始化列表代替赋值操作。
class Test2 { Test1 test1 ; Test2(Test1 &t1):test1(t1){} }
因为static属于类并不属于具体的对象,所以 static成员是不允许在类内初始化的,那么static const 成员是不是在初始化列表中呢?
答案是NO
一是static属于类,它在未实例化的时候就已经存在了,而构造函数的初始化列表,只有在实例化的时候才执行。
二是static成员不属于对象。我们在调用构造函数自然是创建对象,一个跟对象没直接关系的成员要它做什么呢
初始化:从无到有,创建了新对象;如:string foo = “Hello World!”
赋值:没有创建新对象,而是对已有对象赋值。 如:string bar; bar = “Hello World!”
有时我们可以忽略数据成员初始化和赋值之间的差异,但并非总能这样。
如果成员是const或者是引用的话,必须将其初始化。类似的,当成员属于某种类类型且该类没有定义默认构造函数时,也必须将这个成员初始化
成员变量的初始化顺序
#include <iostream> #include <stdio.h> using namespace std; class A { public: int i; int j; A(int x):i(x),j(i){}; void print() { cout<<i<<endl; cout<<j<<endl; } }; int main() { A a(3); a.print(); return 0; }
运行结果:
若将代码该成这样:
A(int x):j(x),i(j){};
运行结果:
这里的i相当于未定义(因为先于j声明)。所以,一个好的习惯是,按照成员定义的顺序进行初始化。
关于const:
在类中声明变量为const类型,const常量的初始化必须在构造函数初始化列表中初始化,而不可以在构造函数函数体内初始化
#include <iostream> using namespace std; class A { public: A(int size) : SIZE(size) {}; private: const int SIZE; }; int main() { A a(100); }
但是,但是,但是:
此时的const变量属于具体的一个对象,如何在整个类中都恒定不变呢?
答案是利用枚举,举例:
#include <iostream> using namespace std; class A { private: enum {SIZE = 100}; public: int array[SIZE]; }; int main() { A a; }
枚举常量不会占据对象的存储空间,在编译时被全部求值
但是,它隐含的数据对象类型为整形,不能表示其他类型。
问题
如何定义在类中定义非整形常量?(待解决)
const成员函数
任何不修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时,不慎修改了数据成员,或调用了其他非const成员函数,编译器就会指出错误。
#include <iostream> using namespace std; class Stack { public: void Push(int item); int Pop(void); int GetCount(void) const; private: int m_num; int m_data[100]; }; int Stack::GetCount(void) const { ++m_num; //编译错误,企图修改数据成员 Pop(); //编译错误,企图调用非const函数 return m_num; }
同一个类中,可以仅通过是否是const定义两个函数名字、参数、返回值完全相同的两个成员函数,例如:
#include <iostream> using namespace std; class A { public: A(int v): val(v) {} void print_val() { cout << "not const:" << val << endl;} void print_val() const { cout << "const print_val:" << val << endl;} private: int val; }; int main(int argc ,char **argv) { A b(45); b.print_val(); const A a(12); a.print_val(); }
输出
结论
同函数名、参数、返回值可以仅通过是否为const来定义为类的两个成员函数。在调用时,const对象调用const成员函数,非const对象调用非const成员函数。
问题 1:
不可以在const函数中改变成员变量的值,那么有没有办法改变?
答案是可以的,把成员变量声明为mutable类型。看程序:
#include <iostream> using namespace std; class A { public: A(int v): val(v) {} void print_val() { cout << "not const:" << val << endl;} void print_val() const { val++; cout << "const print_val:" << val << endl;} private: mutable int val; }; int main(int argc ,char **argv) { A b(45); b.print_val(); const A a(12); a.print_val(); }
结果:
问题2:
当类中只有const函数,非const对象是否可以调用const函数?
答案是可以的,程序:
#include <iostream> using namespace std; class A { public: A(int v): val(v) {} // void print_val() { cout << "not const:" << val << endl;} void print_val() const { val++; cout << "const print_val:" << val << endl;} private: mutable int val; }; int main(int argc ,char **argv) { A b(45); b.print_val(); const A a(12); a.print_val(); }
结果:
但是:只有const函数时,非const对象不可以调用那个const函数(否则,类的数据变量就会发生变化)。
问题3:
当类中存在只有 是否为const 不同的两个函数时,const函数是否可以暂时调用那个非const函数?
答案是可以的。用const_cast将转化掉表达式的const性质
#include <iostream> using namespace std; class A { public: A(int v): val(v) {} void print_val() { cout << "not const:" << val << endl;} void const print_val() const { cout << "const print_val:" << val << endl;} private: int val; }; int main(int argc ,char **argv) { A b(45); b.print_val(); const A *a = new A(45); const_cast<A*>(a)->print_val(); a->print_val(); }
结果:
注意
单纯用类转化不行
const A a(45); const_cast<A> a.print_val();
报错:
问题4:返回类型是const是怎么回事?
const返回类型只有在修饰指针或引用是才有用。单凭const返回类型不可以重载。
相关文章推荐
- 从头认识java-4.8 数组的初始化(2)-可变参数列表
- 类参数初始化列表
- 可变参数列表实现机制与printf()函数源码分析
- 【C语言】printf函数的简单实现(可变参数列表)
- C++参数初始化列表
- 从头认识java-4.8 数组的初始化(2)-可变参数列表
- 关于初始化参数列表使用注意
- C++类构造函数初始化列表,子类向父类传参数
- cpp类的初始化参数列表
- c++ 用参数初始化列表对数据成员初始化
- 可变参数列表:简单printf函数的实现
- 利用可变参数列表简单实现printf函数的功能
- C++类构造函数初始化列表,子类向父类传参数
- C++初始化参数列表对成员函数初始化
- KindEditor初始化参数列表
- PostgreSQL启动过程中的那些事九_十_十一:初始化活跃backend进程列表、创建opts文件、保持非默认GUC参数文件
- C++构造函数中用参数列表初始化成员
- 参数初始化列表
- C语言之隐蔽问题[01 参数传递时参数列表初始化顺序]
- 关于成员初始化参数列表的总结