博文

C++构造函数调用顺序(2010-06-10 19:24:00)

摘要:1、如果类里面有成员类,成员类的构造函数优先被调用; 2、创建派生类的对象,基类的构造函数函数优先被调用(也优先于派生类里的成员类); 3、 基类构造函数如果有多个基类则构造函数的调用顺序是某类在类派生表中出现的
顺序而不是它们在成员初始化表中的顺序;
4、成员类对象构造函数如果有多个成员类对象则构造函数的调用顺序是对象在类中
被声明的顺序而不是它们出现在成员初始化表中的顺序;
5、派生类构造函数
作为一般规则派生类构造函数应该不能直接向一个基类数据成员赋值而是把值传递
给适当的基类构造函数否则两个类的实现变成紧耦合的(tightly coupled)将更加难于
正确地修改或扩展基类的实现。(基类设计者的责任是提供一组适当的基类构造函数)
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/smilelance/archive/2007/03/30/1546849.aspx......

阅读全文(1667) | 评论:0

指针的指针(2010-06-10 11:10:00)

摘要:http://www.99inf.net/SoftwareDev/C/22131_2.htm......

阅读全文(1552) | 评论:0

C语言面试题大汇总之华为面试题(2010-06-09 21:53:00)

摘要:1、局部变量能否和全局变量重名?  答:能,局部会屏蔽全局。要用全局变量,需要使用"::"   局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。  2、如何引用一个已经定义过的全局变量?  答:extern   可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。   3、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?  答:可以,在不同的C文件中以static形式来声明同名全局变量。  可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错   4、语句for( ;1 ;)有什么问题?它是什么意思?   答:和while(1)相同。  5、do……while和while……do有什么区别?  答:前一个循环一遍再判断,后一个判断以后再循环    6、请写出下列代码的输出内容   #include    main()    {     int a,b,c,d;    a=10;     b=a++;     c=++a;     d=10*a++;     printf("b,c,d:%d,%d,%d",b,c,d);     return 0;    }    答:10,12,120    7、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?  全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效,在同一源......

阅读全文(2097) | 评论:0

静态函数 静态数据成员与静态成员函数 为什么虚函数必须是非静态成员函数(2010-06-09 21:45:00)

摘要:静态函数
用static声明的函数是静态函数。静态函数可以分为全局静态函数和类的静态成员函数。

Static关键字
在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化,对于该类的所有对象来说,static成员变量只有一份。
用static声明的方法是静态方法,在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员。
静态方法不再是针对于某个对象调用,所以不能访问非静态成员。
可以通过对象引用或类名(不需要实例化)访问静态成员

C++类静态数据成员与类静态成员函数
函数调用的结果不会访问或者修改任何对象(非static)数据成员,这样的成员声明为静态成员函数比较好。且如果static int func(....)不是出现在类中,则它不是一个静态成员函数,只是一个普通的全局函数,只不过由于static的限制,它只能在文件所在的编译单位内使用,不能在其它编译单位内使用。
静态成员函数的声明除了在类体的函数声明前加上关键字static,以及不能声明为const或者volatile之外,与非静态成员函数相同。出现在类体之外的函数定义不能制定关键字static。
静态成员函数没有this指针。

在没有讲述本章内容之前如果我们想要在一个范围内共享某一个数据,那么我们会设立全局对象,但面向对象的程序是由对象构成的,我们如何才能在类范围内共享数据呢?

这个问题便是本章的重点:声明为static的类成员或者成员函数便能在类的范围内共同享,我们把这样的成员称做静态成员和静态成员函数。

下面我们用几个实例来说明这个问题,类的成员需要保护,通常情况下为了不违背类的封装特性,我们是把类成员设置为protected(保护状态)的,但是我们为了简化代码,使要说明的问题更为直观,更容易理解,我们在此处都设置为public。

以下程序我们来做一个模拟访问的例子,在程序中,每建立一个对象我们设置的类静态成员变自动加一,代码如下:

阅读全文(2042) | 评论:0

构造函数不能是虚函数(2010-06-09 21:32:00)

摘要:首先,让我们假设他是虚的.
当我们在构造函数中时并调用虚函数.大家都知道,对于普通的成员函数虚函数的调用是在运行时决定的(即晚捆绑.因为在编译时无法知道这个对象是属于这个成员函数的那个类,还是属于由他派生出来的类).
然而,在构造函数中调用虚函数时,他所调用的仅仅是本地版本.也就是说,虚函数在构造函数中并不工作!
    第一,在概念上,构造函数的工作是把对象变成存在物。在任何构造函数中,对象可能只是部分被形成—我们只能知道基类已被初始化了,但不知道哪个类是从这个基类继承来的。然而,虚函数是“向前”和“向外”进行调用。它能调用在派生类中的函数。如果我们在构造函数中也这样做,那么我们所调用的函数可能操作还没有被初始化的成员,这将导致灾难的发生。
    第二,。当一个构造函数被调用时,它做的首要的事情之一是初始化它的VPTR。因此,它只能知道它是“当前”类的,而完全忽视这个对象后面是否还有继承者。当编译器为这个构造函数产生代码时,它是为这个类的构造函数产生代码--既不是为基类,也不是为它的派生类(因为类不知道谁继承它)。
所以它使用的VPTR必须是对于这个类的VTABLE。而且,只要它是最后的构造函数调用,那么在这个对象的生命期内,VPTR将保持被初始化为指向这个VTABLE。但如果接着还有一个更晚派生的构造函数被调用,这个构造函数又将设置VPTR指向它的VTABLE,等.直到最后的构造函数结束。VPTR的状态是由被最后调用的构造函数确定的。这就是为什么构造函数调用是从基类到更加派生类顺序的另一个理由。
    但是,当这一系列构造函数调用正发生时,每个构造函数都已经设置VPTR指向它自己的VTABLE。如果函数调用使用虚机制,它将只产生通过它自己的VTABLE的调用,而不是最后的VTABLE(所有构造函数被调用后才会有最后的VTABLE)。
另外,许多编译器认识到,如果在构造函数中进行虚函数调用,应该使用早捆绑,因为它们知道晚捆绑将只对本地函数产生调用。无论哪种情况,在构造函数中调用虚函数都没有结果。
    所以,构造函数不能是虚的,然......

阅读全文(2432) | 评论:0

虚函数定义时遵循的规则(2010-06-09 21:20:00)

摘要:虚函数的定义要遵循以下重要规则:   1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后 联编的。   2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用于有继承关系的类对象,所以普通函数不能说明为虚函数。   3.静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。   4.内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义,但是在编译的时候系统仍然将它看做是非内联的。   5.构造函数不能是虚函数,因为构造的时候,对象还是一片未定型的空间,只有构造完成后,对象才是具体类的实例。   6.析构函数可以是虚函数,而且通常声名为虚函数。   ------------------------------------   构造函数和虚构函数的调用:        如果是子类构造先基类,再子类
     如果是子类析构先子类,再基类
     但如果基类析构不是虚,只调用基类.否则如果基类析构是虚,则先调用子类,再调用基类。
     如果是用new初始化的,必须用delete来释放,否则不调用析构函数。......

阅读全文(1651) | 评论:0

C/C++ 笔试、面试题目大汇总(2010-06-09 20:18:00)

摘要:1.求下面函数的返回值(微软) int func(x)
{
    int countx = 0;
    while(x)
    {
          countx ++;
          x = x&(x-1);
     }
    return countx;
}  假定x = 9999。 答案:8 思路:将x转化为2进制,看含有的1的个数。 2. 什么是“引用”?申明和使用“引用”要注意哪些问题? 答:引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。 3. 将“引用”作为函数参数有哪些特点? (1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。 (2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。 (3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针......

阅读全文(1145) | 评论:0

高难度面试题求解(C++)(初级)(2010-06-08 21:12:00)

摘要:C++面试题(初级)
姓名______ 日期_______

1:写出输出

void fun(int i) {
static int value=i++;
cout<<value;
}

int main() {
fun(0);
fun(1);
fun(2);
}


2:引用和指针之间有什么区别?

3:比较全局变量和静态变量,试说明两者有何异同.

4:分析代码,给出i,j,k的结果.

int i,j,k;
i=j=k=0;
if(++i||j++||++k) {}

5:说出如下const声明的含义:
1.const char* p
2.char const* p
3.char* const p
4.char A::fun() const;

6:编译下面的代码,会有什么结果?

1:
void fun(char);
void fun(char*);
int main()
{
fun(0);
}

2:
void fun(int);
void fun(int*);
int main()
{
fun(0);
}

7:请写出程序运行的结果

class A{
public:
A() { cout<<"A::A()"<<endl;}
~A() { cout<<"......

阅读全文(2245) | 评论:0

详解virtual table(2010-06-07 22:11:00)

摘要:C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。 关于虚函数的使用方法,我在这里不做过多的阐述。大家可以看看相关的C++的书籍。在这篇文章中,我只想从虚函数的实现机制上面为大家 一个清晰的剖析。 当然,相同的文章在网上也出现过一些了,但我总感觉这些文章不是很容易阅读,大段大段的代码,没有图片,没有详细的说明,没有比较,没有举一反三。不利于学习和阅读,所以这是我想写下这篇文章的原因。也希望大家多给我提意见。 言归正传,让我们一起进入虚函数的世界。 虚函数表
对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。 在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了 这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。 这里我们着重看一下这张虚函数表。在C++的标准规格说明书中说到,编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。 这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。 听我扯了那么多,我可以感觉出来你现在可能比以前更加晕头转向了。 没关系,下面就是实际的例子,相信聪明的你一看就明白了。 假设我们有这样的一个类: class Base { public: virtual void f() { cout << "Base::f" << endl; } virtual void g() { cout << "Base::g" << endl; } virtual void h() { c......

阅读全文(1472) | 评论:0

C/C++ 程序设计员应聘常见面试试题深入剖析(2010-06-07 21:33:00)

摘要:1.引言

  本文的写作目的并不在于提供C/C++程序员求职面试指导,而旨在从技术上分析面试题的内涵。文中的大多数面试题来自各大论坛,部分试题解答也参考了网友的意见。

  许多面试题看似简单,却需要深厚的基本功才能给出完美的解答。企业要求面试者写一个最简单的strcpy函数都可看出面试者在技术上究竟达到了怎样的程度,我们能真正写好一个strcpy函数吗?我们都觉得自己能,可是我们写出的strcpy很可能只能拿到10分中的2分。读者可从本文看到strcpy函数从2分到10分解答的例子,看看自己属于什么样的层次。此外,还有一些面试题考查面试者敏捷的思维能力。

  分析这些面试题,本身包含很强的趣味性;而作为一名研发人员,通过对这些面试题的深入剖析则可进一步增强自身的内功。

  2.找错题

  试题1:

void test1()
{
 char string[10];
 char* str1 = "0123456789";
 strcpy( string, str1 );
}
  试题2:

void test2()
{
 char string[10], str1[10];
 int i;
 for(i=0; i<10; i++)
 {
  str1[i] = 'a';
 }
 strcpy( string, str1 );
}
  试题3:

void test3(char* str1)
{
 char string[10];
 if( strlen( str1 ) <= 10 )
 {
  strcpy( string, str1 );
 }
}
  解答:

......

阅读全文(1205) | 评论:0