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

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

2013-08-15 21:53 288 查看
问题 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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: