注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

天马行空

宠辱不惊,闲看庭前花开花落;去留无意,漫观天外云展云舒……

 
 
 

日志

 
 
 
 

C++程序员笔试题3  

2010-11-19 19:00:49|  分类: 程序设计 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

50.String 的具体实现

已知String类定义如下:

class String
{
public:
        String(const char *str = NULL); // 
通用构造函数
           String(const String &another); // 拷贝构造函数
          ~ String(); // 析构函数
           String & operater =(const String &rhs); // 赋值函数
private:
          char *m_data; // 
用于保存字符串
};

尝试写出类的成员函数实现。

String::String(const char *str )

{

    if (str == NULL)

    {

     m_data = new char[1];

      m_data[0] = ‘\0’;

    }

    else

   {

    m_data = new char[strlen(str)+1];

    strcpy(m_data,str)

   }

}

String::String(const String &another)

{

m_data = new char[strlen(another.m_data) + 1];

strcpy(m_data,other.m_data);

}

String::~String()

{

  delete [] m_data;

}

String& String::operater =(const String &rhs)

{

   if(this == rhs)

      return *this;

   delete [] m_data;

   m_data = new char[strlen(rhs.m_data)+1];

   strcpy(m_data,rhs.m_data);

    return *this;

}

51.h头文件中的ifndef/define/endif 的作用?

答:防止该头文件被重复引用。

52.include<file.h> 与 #include "file.h"的区别?

答:前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h

53.C++ 程序中调用被编译器编译后的函数,为什么要加extern C”?

C++语言支持函数重载,C语言不支持函数重载。C++提供了C连接交换指定符号extern C

解决名字匹配问题。

首先,作为externC/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。

通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数

extern "C"是连接申明(linkage declaration),extern "C"修饰的变量和函数是按照C语言方式编译和连接的,来看看C++中对类似C的函数是怎样编译的:

作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:

void foo( int x, int y );
  
该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。

_foo_int_int 这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float

同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。

未加extern "C"声明时的连接方式

假设在C++中,模块A的头文件如下:

// 模块A头文件 moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
  int foo( int x, int y );
#endif
  


在模块B中引用该函数:

// 模块B实现文件 moduleB.cpp
i nclude "moduleA.h"
foo(2,3);

extern "C"声明后的编译和连接方式

extern "C"声明后,模块A的头文件变为:

// 模块A头文件 moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
   extern "C" int foo( int x, int y );
#endif
  


在模块B的实现文件中仍然调用foo( 2,3 ),其结果是:
1)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式;

2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo

如果在模块A中函数声明了fooextern "C"类型,而模块B中包含的是extern int foo( int x, int y ) ,则模块B找不到模块A中的函数;反之亦然。

所以,可以用一句话概括extern C”这个声明的真实目的(任何语言中的任何语法特性的诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留在这个语言是怎么做的,还要问一问它为什么要这么做,动机是什么,这样我们可以更深入地理解许多问题):实现C++C及其它语言的混合编程。  

明白了C++extern "C"的设立动机,我们下面来具体分析extern "C"通常的使用技巧:

extern "C"的惯用法

1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:


extern "C"
{
i nclude "cExample.h"
}

而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。


C++引用C函数例子工程中包含的三个文件的源代码如下:

/* c语言头文件:cExample.h */
#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
extern int add(int x,int y);
#endif


/* c
语言实现文件:cExample.c */
i nclude "cExample.h"
int add( int x, int y )
{
return x + y;
}


// c++
实现文件,调用addcppFile.cpp
extern "C"
{
i nclude "cExample.h"
}
int main(int argc, char* argv[])
{
add(2,3);
return 0;
}

如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern "C" { }


2)在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern "C"的该头文件,应该仅将C文件中将C++中定义的extern "C"函数声明为extern类型。

C引用C++函数例子工程中包含的三个文件的源代码如下:

//C++头文件 cppExample.h
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add( int x, int y );
#endif


//C++
实现文件 cppExample.cpp
i nclude "cppExample.h"
int add( int x, int y )
{
return x + y;
}


/* C
实现文件 cFile.c
/* 
这样会编译出错:#i nclude "cExample.h" */

int main( int argc, char* argv[] )
{
add( 2, 3 );
return 0;
}

 

What is displayed when f() is called given the code:
class Number {
public:
string type; 

Number(): type(
void) { }
explicit Number(short) : type(
short) { } 
Number(int) : type(
int) { }
};
void Show(const Number& n) { cout << n.type; }
void f()
{
short s = 42;
Show(s); 
}
a) void
b) short
c) int
d) None of the above

2. Which is the correct output for the following code
double dArray[2] = {4, 8}, *p, *q;
p = &dArray[0];
q = p + 1;
cout << q 
 p << endl; 
cout << (int)q - (int)p << endl;

 

 


a) 1 and 8
b) 8 and 4
c) 4 and 8
d) 8 and 1

第一个选C
虽然传入的是short类型,但是short类型的构造函数被生命被explicit,也就是只能显示类型转换,不能使用隐式类型转换。
第二个选A
第一个是指针加减,按照的是指向地址类型的加减,只跟类型位置有关,qp指向的数据类型以实际数据类型来算差一个位置,因此是1。而第二个加减是实际指针值得加减,在内存中一个double类型占据8个字节,因此是8

以上内容为转载,原文链接

http://chain2012.blog.163.com/blog/static/133896039200911361153895/

http://chain2012.blog.163.com/blog/static/1338960392009111331618327/

 

  评论这张
 
阅读(287)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018