4、下面类的两种不同的构造函数的区别
Sample::Sample(string name):_name(name){}
Sample::Sample(string name){_name=name;}
解答:
line1是构造函数初始化列表初始化,line2是构造函数体内对成员赋值。
初始化列表初始化 和 构造函数体内初始化的区别主要是在与数据成员的类型。
从概念上讲,可以认为构造函数分两个阶段执行:(1)初始化阶段;(2)普通的计算阶段。
计算阶段由构造函数体内的所有语句完成。
没有在构造函数初始化列表里初始化的成员,使用与初始化变量同样的规则进行初始化。
运行该类型的默认构造函数来初始化类类型的数据成员。局部作用域的内置类型成员不被初始化,
全局作用域的成员初始化为0.
有三种成员必须在初始化列表中初始化:没有默认构造函数的类类型成员、const成员、引用类型成员。
5、类继承后成员变量的可见性(三种类型的变量及public, private类型的继承)
public继承:public >> public, protected>>protected, private >> private
protected继承:public,protected >> protected, private>>private
private继承: all >> private.
7、空类的系统自动产生的函数(至少写4个)
class Sample
{ };
C++中的空类,默认产生的类成员函数:
class Empty
{
public:
Empty(); // 缺省构造函数
Empty(const Empty&); // 拷贝构造函数
~Empty(); // 析构函数
Empty& operator=(const Empty&); // 赋值运算符
Empty* operator&(); // 取值运算符
const Empty* operator&() const; // 取值运算符const
};
8、2 write the output
#include <iostream>
#include <string>
using namespace std;
void println(const std::string& msg)
{
std:cout<<msg<<’\n’;
}
class Base{
public:
Base() {println(“Base::Base()”);virt();}
void f(){println(“Base::f()”);virt();}
virtual void virt(){println(“Base()::virt()”);}
};
class Derived:public Base
{
Derived(){println(“Derived:: Derived ()”);Virt();}
Virtual void virt(){println(“Derived ()::virt()”);}
};
int main(int argc,char* argv[])
{
Derived d;
Base *pB=&d;
PB->f();
}
8.1 (5%) what is the output of the code “pB->f();” above?
8.2 (5%) what is the output of the code “Dervied d;” above?
解答:
8.1:基类类型的指针pBase指向派生类对象,pBase调用基类的非虚函数 f( ) 时,
如果该非虚函数中又调用了虚函数 vf( )。那么调用的 vf() 版本是派生类里的 vf( ) .
其实也很好理解,被调函数A里嵌入的函数B也是由A的主调者调用。
侯捷深入浅出MFC里64页有这么一句话:“ 每一个 '内含虚函数的类 ',编译器都
会为它做出一个虚函数表,表中的每一个元素都指向一个虚函数的地址。此外
编译器也会为类加上一项成员变量,是一个指向虚函数表的指针(常被称为 vptr)
.....实际上,每一个由此类派生出来的对象,都有这么一个vptr,当我们通过这个对象
调用虚函数时,事实上是通过vptr找到虚函数表,再找出虚函数的真正地址。”
看一个例子:
class CBase
{
public:
virtual void vf()
{
cout<<"CBase"<<endl;
}
int a;
};
void main()
{
CBase obj;
sizeof(obj)==8;
// 如果去掉类中的virtual关键词,则sizeof(obj)==4。
//可见,每个由内含虚函数的类派生的对象都含一个vptr.
}
8.2. 实际上当构造函数已经执行到内部的语句时,这个对象已经构造出来了。
那么构造函数内部调用其他的成员函数,就是通过这个刚刚构造出来的对象
调用的。
因此,本例中Drived d;构造过程中,先调用基类的构造函数构造基类部分,
再调用派生类的构造函数构造派生类独有部分。当派生类的构造函数执行到
构造函数体内的时候,该对象已经完全构造出来了,那么派生类构造函数中
的函数调用是由刚刚构造出的这个对象调用的。因此virt()是由这个新对象的
隐含的vptr调用的派生类版本virt()。