Chapter 18: 多继承和虚拟继承
多继承中两父类的同名函数,在子类中不作为函数重载来处理
#include <iostream>
using namespace std;
class base1
{
public:
void prt(int i)
{
cout << "base1::prt"<<endl;
};
};
class base2
{
public:
void prt()
{
cout << "base2:prt"<<endl;
};
};
class deliver: public base1, public base2
{
public:
void hello()
{
cout << "deliver::hello"<<endl;
};
};
int main()
{
deliver d;
d.prt();//compile error: for two baseX::prt
return 0;
}
18.3.2 免除exempting 个别成员的私有继承影响
派生类只能将继承得到的成员恢复到原来的访问级别该访问级别不能比基类中原来指
定的级别更严格或更不严格
按照下面例子:bc6中可以
#include <iostream>
using namespace std;
class base1
{
public:
void prt(int i)
{
cout << "base1::prt"<<endl;
};
public:
int m_pubI;
protected:
int m_proI;
private:
int m_prvI;
};
class base2
{
public:
void prt()
{
cout << "base2:prt"<<endl;
};
};
class deliver: private base1, public base2
{
public:
void hello()
{
cout << "deliver::hello"<<endl;
};
public:
private :
private:
using base1::m_pubI;
using base1::m_proI;
};
int main()
{
deliver d;
//d.prt();//compile error: for two baseX::prt
return 0;
}
迟缓型分配策略(lazy allocation strategy)
18.5 虚拟继承(virtual inheritance)
c++ 的继承两种: 按值继承(就是:public class),按引用继承(就是:public virtual class),这就是
虚拟继承.
class Bear : public ZooAnimal { ... };
每个Bear 类对象都含有其ZooAnimal 基类子对象的所有非静态数据成员,以及在Bear中声明的非静态数
据成员。
为了解决多继承中多个子类重复,产生二义性
iostream的继承方式
-虚拟继承, + 非虚拟继承
istream
- +
ios + iostream
- +
ostream
类似如下:
istream : public virtual ios;
ostream : public virtual ios;
iostream : public istream,public ostream;
虚拟基类的初始化变成了最终派生类most derived class 的责任。
这个最终派生类是由每个特定类对象的声明来决定的。
#include <iostream>
#include <string>
using namespace std;
class base
{
public:
base(string& name, int i):m_name(name),m_AttrID(i)
{
cout << "base::base"<<endl;
};
private:
string m_name;
int m_AttrID;
};
class son1: virtual public base
{
public:
son1(string& name):base(name,1)
{
cout << "son1::son1"<<endl;
};
};
class son2: virtual public base
{
public:
son2(string& name):base(name,2)
{
cout << "son2::son2"<<endl;
};
};
/*
class dev : public son1 , public son2
{
public:
dev(string& name):base(name,3),son1(name),son2(name) //这里dev 调用son1,son2,但
是缺不是对应的属性ID,对于dev应为3
{
};
};
*/
class dev: public son1, public son2
{
public:
dev(string& name):base(name, 3),son1(name),son2(name)
{
cout << "dev::dev"<<endl;
};
};
int main()
{
string s = "sadf";
dev d(s);
return 0;
};
18.5.3 构造函数与析构函数顺序
无论虚拟基类出现在继承层次中的哪个位置上,它们都是在非虚拟基类之前被构造.
19.1.1 dynamic_cast 操作符
dynamic_cast 操作符可以用来把一个类类型对象的指针转换成同一类层次结构中的其他类的指针.
同时也可以用它把一个类类型对象的左值转换成同一类层次结构中其他类的引用.
好像这个用的比较少:
dynamic_cast< Type& >( lval )
如果用来转指针,可以用dynamic_cast结果码是否为0判断是否成功,非0 成功。
形如 if ( programmer *pm = dynamic_cast< programmer* >( pe ) )
如果用来转引用,因为不存在空引用,所以将抛出异常,捕捉形式如下:
try {
programmer &rm = dynamic_cast< programmer & >( re );
// 用 rm 调用 programmer::bonus()
}
catch ( std::bad_cast ) {
// 使用 employee 的成员函数
}
typeid 操作符它在程序中可用于获取一个表达式的类型。
如果表达式是一个类类型,并且含有一个或多个虚拟成员函数,则答案会不同于表达式本身的类型.
当typeid 操作符的操作数是类类型,但不是带有虚拟函数的类类型时typeid 操作符会指出操作数的类型,
而不是底层对象的类型.
19.2
异常对象有throw创建,有编译器决定(依赖于编译器)是否直接在异常对象存储区建立异常对象,如果
否 则是先创建一个临时对象,再通过拷贝构造函数拷贝到此存储区