1、C++中有一种设计原则叫依赖倒置。也是基于多态的。
2、高层模块不应该依赖低层模块,二者都依赖其抽象;抽象不依赖细节;细节依赖抽象。
3、依赖倒置的意义:
(1)以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。
(2)依赖倒置原则可以降低类间的耦合性,提高系统稳定性,降低修改程序造成的风险。
(3)抽象类(c++中称为接口)。(例如类Absbook 中的virtual string getContent() = 0;)
(4)细节就是具体的实现类。(例如类Book/Book2中的string getContent())
4、实例:妈妈讲故事
#include
#include
using namespace std;
class Absbook
{
public:
virtual string getContent() = 0;
};
class Book : public Absbook
{
public:
string getContent()
{
return "西游记 ";
}
};
class Book2 : public Absbook
{
public:
string getContent()
{
return "红楼梦 ";
}
};
class Mother
{
public:
void tellstory(Absbook *book)
{
cout << book->getContent() ;
}
};
int main()
{
Mother *mother = new Mother;
Absbook *book;
book = new Book;
cout << "妈妈讲 " ;
mother->tellstory(book);
cout << "的故事" << endl;
book = new Book2;
cout << "妈妈讲 " ;
mother->tellstory(book);
cout << "的故事" << endl;
return 0;
}
运行结果:
1、运算符typeid
(1)运算符typeid 返回包含操作数数据类型信息的type_info 对象的一个引用,信息中包括数据类型的名称。
(2)type_info 重载了操作符 = =, !=,分别用来比较是否相等、不等,函数name()返回类型名称。
(3)type_info 的拷贝和赋值均是私有的,故不可拷贝和赋值。
2、多态下使用typeid 时要注意的问题:
(1)确保基类定义了至少一个虚函数(虚析构也算)。
(2)不要将typeid 作用于指针,应该作用于引用,或解引用的指针。
(3)type_info 类型,其拷贝构造函数和赋值运算函数都声明为private,这意味着其不能用于stl 容器。
3、示例:
#include
using namespace std;
class A
{
public:
virtual void func()
{
cout << "A func" << endl;
}
int m_num;
};
class B : public A
{
public:
void func()
{
cout << "B func" << endl;
}
};
class C : public A
{
public:
void func()
{
cout << "C func" << endl;
}
};
void test(A *pa)
{
if(typeid(*pa).name() == typeid(B).name()) //判断指针指向的类型
pa -> func();
}
int main()
{
A a;
B b;
C c;
A *pa;
B *pb;
pa = &b;
test(pa);
pa = &c;
test(pa);
cout << typeid(pa).name() << endl; //class A *
cout << typeid(*pa).name() << endl; //class A -virtual- class B
return 0;
}
运行结果:(test中不加typeid与加上后的效果对比)
1、作用:一种运行时的类型转化方式,所以要在运行时作转换判断。
(1)若对指针进行dynamic_cast,失败返回NULL,成功返回正常cast后的对象指针;
(2)若对引用进行dynamic_cast,失败抛出异常,成功返回正常cast后的对象引用。
2、dynamic_cast 常用多态继承中,判断父类指针的真实指向。
3、在类层次间进行上行转换时,dynamic_cast和static_cast效果一样;进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
注:C++上行转换:子类对象赋值给基类对象,子类的对象指针赋值给基类的对象指针。
C++下行转换:只可以基类的对象指针赋值给子类的对象指针。(前提:多态)
4、注意事项:由于使用dynamic_cast无论是否转换成功都会通过,所以转换后加if()进行检查是否转换成功。
5、示例:
#include
using namespace std;
class A
{
public:
virtual void func()
{
cout << "A func" << endl;
}
};
class B : public A
{
public:
void func()
{
cout << "B func" << endl;
}
int num;
};
class C : public A
{
public:
void func()
{
cout << "C func" << endl;
}
};
int main()
{
A a;
B b;
C c;
b.num = 11;
A &ra = b;
b = dynamic_cast(ra); //A &ra = c;时会抛出异常
//A *pa = &a;
A *pa = &b;
B *pb = &b;
C *pc = &c;
//C++上行转换:子类对象赋值给基类对象,子类的对象指针赋值给基类的对象指针
// a = static_cast(b);
// pa = static_cast(pb);
//C++下行转换:基类的对象指针赋值给子类的对象指针(前提:多态)
//注意:基类对象赋值给子类对象不可行
//使用dynamic_cast,如果失败返回nullptr
//b = dynamic_cast(a); //不可行
pb = dynamic_cast(pa);
//检查pa是否指向一个B类型的对象,如果是则进行转换,如果不是则返回nullptr
if(pb != nullptr)
{
pb->func();
cout << pb->num <