第15章 面向对象编程
【106】15.1哪些成员函数可以定义为虚成员?
答:除了构造函数外,任意非static成员函数都可以为虚成员;
【107】15.16对于下面的基类定义:
structBase{
Base(intval):id(val){}
protected:
intid;
}
解释为什么下述每个构造函数是非法的。
a)struct C1:public Base{
C1(intval):id(val){}
};
没有在初始化列表中向基类构造函数传递实参;
b)struct C2:public C1{
C2(intval):Base(val),C1(val){}
};
初始化列表中出现了非直接基类Base;
c)struct C3:public C1{
C3(intval):Base(val){}
};
初始化列表中出现了非直接基类Base而没有出现直接基类C1;
d)structC4:public Base{
C4(intval):Base(id+val){}
};
初始化列表中使用了未定义的变量id;
e)struct C5:public Base{
C5(){}
};
缺少初始化列表:Base类没有默认构造函数,其派生类必须用初始化列表的构造函数传递实参;
【108】15.17说明在什么情况下类应该具有虚析构函数?
答:作为基类使用的类应该具有析构函数,以保证在删除(指向动态分配对象的)基类指针时,根据指针实际指向的对象所属的类型运行适当的析构函数。
【109】15.23对于下面的基类和派生类定义:
structBase{
foo(int);
protected:
intbar;
doublefoo_bar;
};
structDerived:public Base{
foo(string);
boolbar(Base *pb);
voidfoobar();
protected:
stringbar;
};
找出下述每个例子中的错误并说明怎样改正:
a)Derivedd;d.foo(1024);
调用foo函数所给定的实参类型错误。通过Derived类对象d调用foo函数,调用到的是Derived类中定义的foo函数,应使用string类型的实参。
b)voidDerived::foobar(){ bar =1024;}
用int型值1024对bar进行赋值错误。在Derived类中定义的数据成员bar屏蔽了基类Base中的同名成员,所以此处访问到的是Derived类中定义的bar,应赋以string类型的对象或C风格字符串。
c)boolDerived::bar(Base *pb)
{return foo_bar==pb->foo_bar;}
通过指向Base类对象的指针访问其受保护成员foo_bar错误。可改正为将pb定义为指向Derived类对象的指针。
【110】15.25假定Derived继承Base,并且Base将下面的函数定义为虚函数;假定Derived打算定义自己的这个虚函数版本,确定在Derived中哪个声明是错误的,并指出为什么错。
a)Base*Base::copy(Base*);
Base* Derived::copy(Derived*);
单纯从语法上看并没有错,但Derived中声明的copy是一个非虚函数,而不是对Base中声明的虚函数copy的重定义,因为派生类中重定义了的虚函数必须具有与基类中虚函数相同的原型(唯一的例外是返回类型可以稍有不同)。而且Derived中定义的copy函数还屏蔽了基类Base的copy函数。
b)Base*Base::copy(Base*);
Derived* Derived::copy(Base*);
c)ostream&Base::print(int,ostream&=cout);
ostream&Derived::print(int,ostream&);
d)voidBase::eval() const;
void Derived::eval();