您的位置:首页 > 编程语言 > C语言/C++

有点意思的C/C++问题及解答:6-10

2014-03-25 22:05 344 查看
http://blog.csdn.net/wuzhekai1985/article/details/6628212

问题 6:非C++内建型别A 和B,在哪几种情况下B 能隐式转化为A? 

(1)class A { ...... };  class B : public A { ……} ;  // B 公有继承自A,可以是间接继承的

(2)class A { ...... }; class B {  operator A() { return A::A(); } ......};  // B 实现了到A 的类型转化

(3)class A { A( const B& ); } ; // A 实现了non-explicit 的参数为B(可以有其他带默认值的参数)构造函数 

提供隐式转换时,应避免出现二义性。比如上面的几种方式,如果即定义了(2)又定义了(3),就存在二义性。因为编译器可以用两种方式将B转换为A,一是用A的构造函数,另一种是用B的类型转换符。最佳实践:避免二义性最好的办法是避免编写互相提供隐式转换的成对的类。《C++ Primer》。

问题 7:下面这个程序有什么问题?

[cpp] view
plaincopyprint?

#include <iostream>  

using namespace std;  

class A  

{  

private:  

    int value;  

public:  

    A(int n) { value = n; }  

    A(A other){ value = other.value; }  

    void Print(){ cout << value << endl; }  

};  

int main()  

{  

    A a = 10;  

    A b = a;  

    b.Print();  

    return 0;  

}  

编译错误, A(A other){}  这个复制构造函数定义有误,该函数的形参只能是本类类型对象的引用,常用const修饰《C++ Primer》。应该改成这样 A(const A&other) { value = other.value; }。复制构造函数可以用于:

(1)根据另一个同类型的对象显示或隐式初始化一个对象

string s = "hello"; 

首先会调用接受一个C风格字符串形参的string构造函数,创建临时对象,然后调用复制构造函数,将s初始化为那个临时对象的副本。

(2)复制一个对象,将它作为实参传递给一个函数

void foo(string s);

(3)从函数返回复制一个对象

string foo();

(4)初始化容器中的元素。

vector<string> svec(5); 

首先调用string默认构造函数创建一个临时值,然后将这个临时值复制给svec的每一个元素,即调用string复制构造函数。

(5)根据元素初始化列表初始化数组元素

比如下面这个函数,初始化数组a 时调用的是复制构造函数。而初始化数组b时调用的是默认构造函数。而初始化数组c时,由于它有4个元素,而初始化列表只有2个,因此前两个元素的初始化调用复制构造函数,后两个元素的初始化调用默认构造函数。

[cpp] view
plaincopyprint?

#include <iostream>  

using namespace std;  

class A  

{  

public:  

    A()  { value=1;cout<<"A Default Constructor"<<endl;}  

    A(int v) {value=v;cout<<"A Copy Constructor"<<endl;}  

    int value;  

};  

int main()  

{  

    A a[2]={1,2};  

        A b[2];  

        A c[4]={1,2};  

    return 0;  

}  

问题8:构造函数、静态函数、内联函数可不可以是虚函数?

构造函数和静态函数不可以、内联函数可以

构造函数不可以为虚函数:虚函数的调用是通过一个虚指针来实现的,而这个虚指针是在构造过程中设定的。

静态函数不可为虚函数:静态函数的调用是不需要实例的,而虚函数需要通过从一个实例中获取虚指针,进而获取函数的地址,从而实现动态绑定。

内联函数可以:内联是在编译阶段用代码换调用,而虚函数是在运行期动态绑定。虽然可以,但是一般不会这样做,代价太大了。

问题9:析构函数必须是虚函数吗?

答案是并不是必须的。如果类被设计成能被继承,析构函数必须是虚函数。否则可以不为虚函数。析构函数写成虚函数主要是为了在实现多态时不造成内存泄露。比如下面这段程序,B的析构函数不会被调用,如果将A的析构函数写成虚函数,则B的析构函数可以被调用。

[cpp] view
plaincopyprint?

#include <iostream>  

using namespace std;  

class A  

{  

public:  

    A() {cout<<"A Constructor\n";}  

    ~A() {cout<<"A Destructor\n";}  

};  

class B:public A  

{  

public:  

    B() { cout<<"B Constructor\n";}  

    ~B() { cout<<"B Destructor\n";}  

};  

   

int main()  

{  

        A *pa=new B();  

    delete pa;  

    return 0;  

}  

问题10:下面这个程序的输出是什么?

[cpp] view
plaincopyprint?

#include <iostream>  

using namespace std;  

struct Point3D  

{  

    int x;  

    int y;  

    int z;  

};  

   

int main()  

{  

    Point3D* pPoint = NULL;  

    int offset = (int)(&(pPoint->z));  

    cout<<offset<<endl;  

    return 0;  

}  

这个程序输出为8,&(pPoint->z)取成员变量z的地址,并不需要访问内存,所以只要将pPoint指向的地址加上变量z在类中偏移量,结果为8。

如果是&(pPoint->x)和&(pPoint->y),则结果为0和4。

如果pPoint不为空,例如 Point3D* pPoint = new Point3D;  三个成员变量的地址依次相差4。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: