C++002常见设计模式
2016-04-22 14:53
162 查看
饿汉式的单例模式
1.1 问题
单例模式使用私有构造函数的方法禁止在类外部创建实例,而类自己使用静态成员变量的方法来维护其唯一实例,并提供访问该实例的方法。饿汉式单例模式的优点是加载进程时静态创建单例对象,线程安全;缺点是无论使用与否,总要创建一个实例。
1.2 步骤
实现此案例需要按照如下步骤进行。步骤一:饿汉式的单例模式
代码如下:
#include <iostream> class Singleton { private: Singleton (void) { } Singleton (Singleton const& that) { } static Singleton s_instance; public: static Singleton& getInstance (void) { return s_instance; } }; Singleton Singleton::s_instance; int main(int argc, const char * argv[]) { Singleton& a = Singleton::getInstance(); std::cout << std::hex << &a << std::endl; Singleton& b = Singleton::getInstance(); std::cout << std::hex << &b << std::endl; return 0; }
上述代码中,以下代码:
private: Singleton (void) { } Singleton (Singleton const& that) { }
通过将类Singleton的构造函数和拷贝构造函数定义成私有的,来禁止在类外创建该类的对象。
上述代码中,以下代码:
static Singleton s_instance;
将单例类的唯一对象实例,实现为其静态成员变量。虽然静态成员变量s_instance需要在类的外部实例化,但它毕竟是Singleton类的成员(尽管是静态成员),依然属于类的内部元素,可以调用该类的私有构造函数。
上述代码中,以下代码:
static Singleton& getInstance (void) { return s_instance; }
通过成员函数getInstance来获得类Singleton的唯一对象实例。
1.3 完整代码
本案例的完整代码如下所示:#include <iostream> class Singleton { private: Singleton (void) { } Singleton (Singleton const& that) { } static Singleton s_instance; public: static Singleton& getInstance (void) { return s_instance; } }; Singleton Singleton::s_instance; int main(int argc, const char * argv[]) { Singleton& a = Singleton::getInstance(); std::cout << std::hex << &a << std::endl; Singleton& b = Singleton::getInstance(); std::cout << std::hex << &b << std::endl; return 0; }
2 懒汉式的单例模式
2.1 问题
单例模式使用私有构造函数的方法禁止在类外部创建实例,而类自己使用静态成员变量的方法来维护其唯一实例,并提供访问该实例的方法。懒汉式单例模式的优点是用则创建,不用不创建,什么时候用什么时候创建;缺点是首次访问时动态创建单例对象,在多线程应用中,存在线程不安全的问题。
2.2 步骤
实现此案例需要按照如下步骤进行。步骤一:懒汉式的单例模式
代码如下:
#include <iostream>
class Singleton
{
private: Singleton (void) { } Singleton (Singleton const& that) { }static Singleton* s_instance;
public:
static Singleton& getInstance (void)
{
if (! s_instance)
s_instance = new Singleton;
return *s_instance;
}
};
Singleton* Singleton::s_instance = NULL;
int main(int argc, const char * argv[])
{
Singleton& a = Singleton::getInstance();
std::cout << std::hex << &a << std::endl;
Singleton& b = Singleton::getInstance();
std::cout << std::hex << &b << std::endl;
return 0;
}
上述代码中,以下代码:
private: Singleton (void) { } Singleton (Singleton const& that) { }
通过将类Singleton的构造函数和拷贝构造函数定义成私有的,来禁止在类外创建该类的对象。
上述代码中,以下代码:
static Singleton* s_instance;
声明了类Singleton的静态指针,该指针在类外定义时,被初始化为空,如以下代码所示:
Singleton* Singleton::s_instance = NULL;
上述代码中,以下代码:
static Singleton& getInstance (void) { if (! s_instance) s_instance = new Singleton; return *s_instance; }
通过成员函数getInstance来获得类Singleton的唯一对象实例。与饿汉式的区别是在函数getInstance第一次被调用时,才创建唯一对象实例,而不是在创建程序一开始就创建唯一对象实例。
2.3 完整代码
本案例的完整代码如下所示:#include <iostream>
class Singleton
{
private: Singleton (void) { } Singleton (Singleton const& that) { }static Singleton* s_instance;
public:
static Singleton& getInstance (void)
{
if (! s_instance)
s_instance = new Singleton;
return *s_instance;
}
};
Singleton* Singleton::s_instance = NULL;
int main(int argc, const char * argv[])
{
Singleton& a = Singleton::getInstance();
std::cout << std::hex << &a << std::endl;
Singleton& b = Singleton::getInstance();
std::cout << std::hex << &b << std::endl;
return 0;
}
3 考虑线程安全的单例模式
3.1 问题
饿汉式单例模式在多线程应用中,由于是多线程并发执行,有可能创建出多个对象实例,存在线程不安全的问题。借助互斥锁能够防止单例对象在不同线程中被重复创建。3.2 步骤
实现此案例需要按照如下步骤进行。步骤一:考虑线程安全的单例模式
代码如下:
#include <iostream>
class Singleton
{
private: Singleton (void) { } Singleton (Singleton const& that) { }static Singleton* s_instance;
static pthread_mutex_t s_mutex;
public:
static Singleton& getInstance (void)
{
if (! s_instance)
{
pthread_mutex_lock (&s_mutex);
if (! s_instance)
s_instance = new Singleton;
pthread_mutex_unlock (&s_mutex);
}
return *s_instance;
}
};
Singleton* Singleton::s_instance = NULL;pthread_mutex_t Singleton::s_mutex = PTHREAD_MUTEX_INITIALIZER;_
int main(int argc, const char * argv[])
{
Singleton& a = Singleton::getInstance();
std::cout << std::hex << &a << std::endl;
Singleton& b = Singleton::getInstance();
std::cout << std::hex << &b << std::endl;
return 0;
}
上述代码中,以下代码:
static Singleton& getInstance (void) { if (! s_instance) { pthread_mutex_lock (&s_mutex); if (! s_instance) s_instance = new Singleton; pthread_mutex_unlock (&s_mutex); } return *s_instance; }
在获得类Singleton的唯一对象实例的成员函数getInstance中,通过加互斥锁的方法来保证多线程安全。如下代码:
pthread_mutex_lock (&s_mutex);
首先设置互斥变量s_mutex,此时如果有其它线程已经设置了该变量,则当前线程就等待,直到其他线程释放互斥变量,此线程才重新开始执行。
以下代码:
pthread_mutex_unlock (&s_mutex);
是释放互斥变量s_mutex。
3.3 完整代码
本案例的完整代码如下所示:#include <iostream>
class Singleton
{
private: Singleton (void) { } Singleton (Singleton const& that) { }static Singleton* s_instance;
static pthread_mutex_t s_mutex;
public:
static Singleton& getInstance (void)
{
if (! s_instance)
{
pthread_mutex_lock (&s_mutex);
if (! s_instance)
s_instance = new Singleton;
pthread_mutex_unlock (&s_mutex);
}
return *s_instance;
}
};
Singleton* Singleton::s_instance = NULL;pthread_mutex_t Singleton::s_mutex = PTHREAD_MUTEX_INITIALIZER;_
int main(int argc, const char * argv[])
{
Singleton& a = Singleton::getInstance();
std::cout << std::hex << &a << std::endl;
Singleton& b = Singleton::getInstance();
std::cout << std::hex << &b << std::endl;
return 0;
}
4 通过成员指针访问对象
4.1 问题
成员变量指针的本质,就是特定成员变量在类对象实例中的相对地址。成员变量指针解引用,就是根据类对象实例的起始地址,结合成员变量指针中的相对地址,计算出具体成员变量的绝对地址,并访问之。类的静态成员变量不是对象的一部分,不需要根据相对地址计算绝对地址,也不需要通过对象或其指针解引用。成员函数并不存储在对象中,不存在根据相对地址计算绝对地址的问题,但是需要通过对象或对象指针对成员函数指针解引用,其目的只有一个,即提供this指针。类的静态成员函数没有this指针,无需调用对象。
静态成员与对象无关,因此静态成员指针与普通指针并没有任何本质性区别。
4.2 步骤
实现此案例需要按照如下步骤进行。步骤一:通过成员变量指针访问成员变量
代码如下:
#include <iostream> class Student { public: std::string m_name; std::string m_sex; int m_age; int m_no; }; int main(int argc, const char * argv[]) { int Student::*p_age = &Student::m_age; Student student; student.*p_age = 10; std::cout << student.m_age << std::endl; return 0; }
上述代码中,以下代码:
int Student::*p_age = &Student::m_age;
定义了一个成员变量指针p_age,指向类Student的变量成员m_age.
上述代码中,以下代码:
Student student; student.*p_age = 10;
定义了一个类Student的对象student,然后通过成员变量指针p_age,将对象student中的变量成员m_age赋值为10,这被称为解引用。其实,成员变量指针p_age指向的是变量成员m_age在对象student中的相对地址。“.*”是一个独立的运算符,成员指针解引用运算符。
步骤二:通过成员函数指针访问成员函数
代码如下:
#include <iostream> class Student { public: std::string m_name; std::string m_sex; int m_age; int m_no; void who (void) const { std::cout << "我是" << m_name << ",性别" << m_sex << ",今年" << m_age << "岁,学号" << m_no << std::endl; } }; int main(int argc, const char * argv[]) { int Student::*p_age = &Student::m_age; Student student; student.*p_age = 10; std::cout << student.m_age << std::endl; student.m_name = "张三"; student.m_no = 12; student.m_sex = "男"; void (Student::*p_who) (void) const = &Student::who; (student.*p_who)(); return 0; }
上述代码中,以下代码:
void (Student::*p_who) (void) const = &Student::who;
定义了一个成员函数指针p_who,指向类Student的函数成员who。
上述代码中,以下代码:
(student.*p_who)();
通过成员函数指针p_who,调用类Student的成员函数who,这被称为解引用。添加student的目的只有一个,即提供this指针。
步骤三:通过静态成员指针访问静态成员
代码如下:
#include <iostream> class Student { public: std::string m_name; std::string m_sex; int m_age; int m_no; static int s_count; void who (void) const { std::cout << "我是" << m_name << ",性别" << m_sex << ",今年" << m_age << "岁,学号" << m_no << std::endl; } static void inc (void) { s_count++; } }; int Student::s_count = 0; int main(int argc, const char * argv[]) { int Student::*p_age = &Student::m_age; Student student; student.*p_age = 10; std::cout << "age = " << student.m_age << std::endl; student.m_name = "张三"; student.m_no = 12; student.m_sex = "男"; void (Student::*p_who) (void) const = &Student::who; (student.*p_who)(); int* p_count = &Student::s_count; *p_count = 10; std::cout << "count = " << Student::s_count << std::endl; void (*p_inc)(void) = Student::inc; (*p_inc)(); std::cout << "count = " << Student::s_count << std::endl; return 0; }
上述代码中,以下代码:
int* p_count = &Student::s_count; *p_count = 10;
定义了一个静态成员指针变量p_count,指向类Student的静态变量成员s_count。静态成员指针与普通指针并没有任何本质性区别,只是成员指针受访问控制属性约束。
上述代码中,以下代码:
void (*p_inc)(void) = Student::inc;
定义了一个静态成员函数指针p_inc,指向类Student的函数成员inc。
上述代码中,以下代码:
(*p_inc)();
通过静态成员函数指针p_inc,调用类Student的成员函数inc。类的静态成员函数没有this指针,无需调用对象。
4.3 完整代码
本案例的完整代码如下所示:#include <iostream> class Student { public: std::string m_name; std::string m_sex; int m_age; int m_no; static int s_count; void who (void) const { std::cout << "我是" << m_name << ",性别" << m_sex << ",今年" << m_age << "岁,学号" << m_no << std::endl; } static void inc (void) { s_count++; } }; int Student::s_count = 0; int main(int argc, const char * argv[]) { int Student::*p_age = &Student::m_age; Student student; student.*p_age = 10; std::cout << "age = " << student.m_age << std::endl; student.m_name = "张三"; student.m_no = 12; student.m_sex = "男"; void (Student::*p_who) (void) const = &Student::who; (student.*p_who)(); int* p_count = &Student::s_count; *p_count = 10; std::cout << "count = " << Student::s_count << std::endl; void (*p_inc)(void) = Student::inc; (*p_inc)(); std::cout << "count = " << Student::s_count << std::endl; return 0; }上述代码中,以下代码:简单工厂模式
11.1 问题
全部由纯虚函数构成的抽象类称为纯抽象类或接口。面向抽象编程,使得所有基于接口编写的代码,在子类被更替后,无需做任何修改或只需做很少的修改,就能在新子类上正确运行。11.2 步骤
实现此案例需要按照如下步骤进行。步骤一:简单工厂模式代码如下:#include <iostream>
typedef enum ProductTypeTag
{
TypeA,
TypeB,
TypeC
}PRODUCTTYPE;
// Here is the product class
class Product { public: virtual void show() = 0; };
class ProductA : public Product { public: void show(void) { std::cout << "I'm ProductA" << std::endl; } }; class ProductB : public Product { public: void show(void) { std::cout << "I'm ProductB" << std::endl; } }; class ProductC : public Product { public: void show(void) { std::cout << "I'm ProductC" << std::endl; } };
// Here is the Factory class
class Factory { public: Product* CreateProduct(PRODUCTTYPE type) { switch (type) { case TypeA: return new ProductA; case TypeB: return new ProductB; case TypeC: return new ProductC; default: return NULL; } } };
int main(int argc, char *argv[])
{
// First, create a factory object
Factory *ProductFactory = new Factory();
Product *productObjA = ProductFactory->CreateProduct(TypeA);
if (productObjA != NULL)
productObjA->show();
Product *productObjB = ProductFactory->CreateProduct(TypeB);
if (productObjB != NULL)
productObjB->show();
Product *productObjC = ProductFactory->CreateProduct(TypeC);
if (productObjC != NULL)
productObjC->show();
delete ProductFactory;
delete productObjA;
delete productObjB;
delete productObjC;
return 0;
}
class Product { public: virtual void show() = 0; };定义了一个抽象产品类Product。上述代码中,以下代码:
class ProductA : public Product { public: void show(void) { std::cout << "I'm ProductA" << std::endl; } }; class ProductB : public Product { public: void show(void) { std::cout << "I'm ProductB" << std::endl; } }; class ProductC : public Product { public: void show(void) { std::cout << "I'm ProductC" << std::endl; } };定义了3个具体产品类。在这3个类中,分别对纯虚函数show进行了实现。还可能有更多的具体产品类。这样就造成创建对象时,对象多而杂。上述代码中,以下代码:
class Factory { public: Product* CreateProduct(PRODUCTTYPE type) { switch (type) { case TypeA: return new ProductA; case TypeB: return new ProductB; case TypeC: return new ProductC; default: return NULL; } } };定义了一个简单工厂类Factory,其中含有一个成员函数CreateProduct用于生成具体产品对象,以简化创建对象时,对象多而杂的现象。这样就能把对象的创建和操作两部分分离开,方便后期的程序扩展和维护。上述代码中,以下代码:
Factory *ProductFactory = new Factory(); Product *productObjA = ProductFactory->CreateProduct(TypeA); if (productObjA != NULL) productObjA->show();在主程序中,使用简单工厂类Factory的CreateProduct函数生成具体产品对象,用抽象基类Product的指针实现多态。
11.3 完整代码
本案例的完整代码如下所示:#include <iostream>
typedef enum ProductTypeTag
{
TypeA,
TypeB,
TypeC
}PRODUCTTYPE;
// Here is the product class
class Product { public: virtual void show() = 0; };
class ProductA : public Product { public: void show(void) { std::cout << "I'm ProductA" << std::endl; } }; class ProductB : public Product { public: void show(void) { std::cout << "I'm ProductB" << std::endl; } }; class ProductC : public Product { public: void show(void) { std::cout << "I'm ProductC" << std::endl; } };
// Here is the Factory class
class Factory { public: Product* CreateProduct(PRODUCTTYPE type) { switch (type) { case TypeA: return new ProductA; case TypeB: return new ProductB; case TypeC: return new ProductC; default: return NULL; } } };
int main(int argc, char *argv[])
{
// First, create a factory object
Factory *ProductFactory = new Factory();
Product *productObjA = ProductFactory->CreateProduct(TypeA);
if (productObjA != NULL)
productObjA->show();
Product *productObjB = ProductFactory->CreateProduct(TypeB);
if (productObjB != NULL)
productObjB->show();
Product *productObjC = ProductFactory->CreateProduct(TypeC);
if (productObjC != NULL)
productObjC->show();
delete ProductFactory;
delete productObjA;
delete productObjB;
delete productObjC;
return 0;
}
12 模板方法模式
12.1 问题
全部由纯虚函数构成的抽象类称为纯抽象类或接口。面向抽象编程,使得所有基于接口编写的代码,在子类被更替后,无需做任何修改或只需做很少的修改,就能在新子类上正确运行。12.2 步骤
实现此案例需要按照如下步骤进行。步骤一:模板方法模式代码如下:#include <iostream> class Abstract { protected: virtual void PrimitiveOperation1() = 0; virtual void PrimitiveOperation2() = 0; public: void TemplateMethod() { std::cout << "TemplateMethod" << std::endl; PrimitiveOperation1(); PrimitiveOperation2(); } }; class ConcreteA : public Abstract { protected: virtual void PrimitiveOperation1() { std::cout << "ConcreteA Operation1" << std::endl; } virtual void PrimitiveOperation2() { std::cout << "ConcreteA Operation2" << std::endl; } }; class ConcreteB : public Abstract { protected: virtual void PrimitiveOperation1() { std::cout << "ConcreteB Operation1" << std::endl; } virtual void PrimitiveOperation2() { std::cout << "ConcreteB Operation2" << std::endl; } }; int main() { Abstract *pAbstractA = new ConcreteA; pAbstractA->TemplateMethod(); Abstract *pAbstractB = new ConcreteB; pAbstractB->TemplateMethod(); delete pAbstractA; delete pAbstractB; }上述代码中,以下代码:
class Abstract { protected: virtual void PrimitiveOperation1() = 0; virtual void PrimitiveOperation2() = 0; public: void TemplateMethod() { std::cout << "TemplateMethod" << std::endl; PrimitiveOperation1(); PrimitiveOperation2(); } };定义了抽象模板类Abstract。在该类中,定义两个抽象的原语操作纯虚函数PrimitiveOperation1和纯虚函数PrimitiveOperation2,用这两个原语操作定义一个抽象算法的两个步骤。在该类中还定义了一个模板成员函数TemplateMethod负责整合两个原语操作及其它一些操作,形成一个不变的算法流程。上述代码中,以下代码:
class ConcreteA : public Abstract { protected: virtual void PrimitiveOperation1() { std::cout << "ConcreteA Operation1" << std::endl; } virtual void PrimitiveOperation2() { std::cout << "ConcreteA Operation2" << std::endl; } }; class ConcreteB : public Abstract { protected: virtual void PrimitiveOperation1() { std::cout << "ConcreteB Operation1" << std::endl; } virtual void PrimitiveOperation2() { std::cout << "ConcreteB Operation2" << std::endl; } };定义了两个实体类,在这两个实体类中,各自实现两个具体的原语操作,完成各自实体中的具体算法的各步骤的具体操作。这样如果再有其它的具体算法,只需要再定义一个实体类,实现具体的原语操作即可。上述代码中,以下代码:
Abstract *pAbstractA = new ConcreteA; pAbstractA->TemplateMethod();在主程序中,用抽象模板类Abstract的指针指向实体类ConcreteA,完成一个具体的算法。
12.3 完整代码
本案例的完整代码如下所示:#include <iostream> class Abstract { protected: virtual void PrimitiveOperation1() = 0; virtual void PrimitiveOperation2() = 0; public: void TemplateMethod() { std::cout << "TemplateMethod" << std::endl; PrimitiveOperation1(); PrimitiveOperation2(); } }; class ConcreteA : public Abstract { protected: virtual void PrimitiveOperation1() { std::cout << "ConcreteA Operation1" << std::endl; } virtual void PrimitiveOperation2() { std::cout << "ConcreteA Operation2" << std::endl; } }; class ConcreteB : public Abstract { protected: virtual void PrimitiveOperation1() { std::cout << "ConcreteB Operation1" << std::endl; } virtual void PrimitiveOperation2() { std::cout << "ConcreteB Operation2" << std::endl; } }; int main() { Abstract *pAbstractA = new ConcreteA; pAbstractA->TemplateMethod(); Abstract *pAbstractB = new ConcreteB; pAbstractB->TemplateMethod(); delete pAbstractA; delete pAbstractB; }
13 单继承虚表模型
13.1 问题
编译器会为每个包含虚函数的类生成一张虚函数表,即存放每个虚函数地址的函数指针数组,简称虚表(vtbl)。13.2 步骤
实现此案例需要按照如下步骤进行。步骤一:单继承虚表模型代码如下:#include <iostream> class Base { public: virtual int f1 (void) { std::cout << "Base f1" << std::endl; return 0; } virtual void f2 (int i) { std::cout << "Base f2" << std::endl; } virtual int f3 (int i) { std::cout << "Base f3" << std::endl; return 0; } }; class Derived : public Base { public: int f1 (void) { std::cout << "Derived f1" << std::endl; return 0; } int f3 (int i) { std::cout << "Derived f3" << std::endl; return 0; } virtual void f4 (void) { std::cout << "Derived f4" << std::endl; } }; int main() { Base *b = new Base; b->f3(10); delete b; b = new Derived; b->f3(20); delete b; }上述代码中,以下代码:
class Base { public: virtual int f1 (void) { std::cout << "Base f1" << std::endl; return 0; } virtual void f2 (int i) { std::cout << "Base f2" << std::endl; } virtual int f3 (int i) { std::cout << "Base f3" << std::endl; return 0; } };定义了一个类Base,该类中含有三个虚函数。编译器会为类Base生成一张虚函数表,该表是用于存放每个虚函数地址的函数指针数组,简称虚表(vtbl),每个虚函数对应一个虚函数表中的数组元素。即vtbl[0]->f1,vtbl[1]->f2,vtbl[2]->f3。除了为类Base生成虚函数表以外,编译器还会为类Base增加一个隐式的成员变量,通常在该类实例化对象的起始位置,用于存放虚函数表的首地址,该变量被称为虚函数表指针,简称虚指针(vptr)。即vptr = &vtbl[0]。这样,主程序中以下语句:
Base *b = new Base; b->f3(10);相当于:
Base *b = new Base; b->vptr[2](10);虚表是一个类一张,而不是一个对象一张,同一个类的多个对象,通过各自的虚指针,共享同一张虚表。上述代码中,以下代码:
class Derived : public Base { public: int f1 (void) { std::cout << "Derived f1" << std::endl; return 0; } int f3 (int i) { std::cout << "Derived f3" << std::endl; return 0; } virtual void f4 (void) { std::cout << "Derived f4" << std::endl; } };定义了子类Derived,并且在子类Derived中覆盖了基类Base的f1和f3,继承了基类Base的f2,增加了自己的f4,编译器同样会为子类生成一张专属于它的虚表。指向子类Derived虚表的虚指针就存放在子类对象的基类子对象中,通常还是在起始位置。这样,主程序中以下语句:
b = new Derived; b->f3(20);相当于:
b = new Derived; b->vptr[2](20);此时vptr[2]中存放的是子类Derived中覆盖基类Base的f3,而这就是所谓的多态。
13.3 完整代码
本案例的完整代码如下所示:#include <iostream> class Base { public: virtual int f1 (void) { std::cout << "Base f1" << std::endl; return 0; } virtual void f2 (int i) { std::cout << "Base f2" << std::endl; } virtual int f3 (int i) { std::cout << "Base f3" << std::endl; return 0; } }; class Derived : public Base { public: int f1 (void) { std::cout << "Derived f1" << std::endl; return 0; } int f3 (int i) { std::cout << "Derived f3" << std::endl; return 0; } virtual void f4 (void) { std::cout << "Derived f4" << std::endl; } }; int main() { Base *b = new Base; b->f3(10); delete b; b = new Derived; b->f3(20); delete b; }
14 动态类型转换
14.1 问题
动态类型转换(dynamic_cast)用于将基类类型的指针或引用转换为其子类类型的指针或引用,前提是子类必须从基类多态继承,即基类包含至少一个虚函数14.2 步骤
实现此案例需要按照如下步骤进行。步骤一:动态类型转换代码如下:#include <iostream> class Base { public: virtual int f1 (void) { std::cout << "Base f1" << std::endl; return 0; } }; class Derived : public Base { public: int f1 (void) { std::cout << "Derived f1" << std::endl; return 0; } }; int main() { Derived d; Base* pa = &d; Derived* pb = dynamic_cast<Derived*> (pa); if (pb == NULL) std::cout << "转换失败!" << std::endl; Base& ra = d; try { Derived& rb = dynamic_cast<Derived&> (ra); } catch (std::bad_cast& ex) { std::cout << "转换失败!" << std::endl; } Derived b = dynamic_cast<Derived> (*pa); return 0; }上述代码中,以下代码:
Derived d; Base* pa = &d; Derived* pb = dynamic_cast<Derived*> (pa);应用动态类型转换,将基类Base类型的指针转换为其子类Derived类型的指针。上述代码中,以下代码:
if (pb == NULL) std::cout << "转换失败!" << std::endl;针对指针的动态类型转换,以返回空指针(NULL)表示失败。上述代码中,以下代码:
Base& ra = d; try { Derived& rb = dynamic_cast<Derived&> (ra); }应用动态类型转换,将基类Base类型的引用转换为其子类Derived类型的引用。上述代码中,以下代码:
Base& ra = d; try { Derived& rb = dynamic_cast<Derived&> (ra); }catch (std::bad_cast& ex)针对引用的动态类型转换,以抛出bad_cast异常表示失败。上述代码中,以下代码:
{
std::cout << "转换失败!" << std::endl;
}
Derived b = dynamic_cast<Derived> (*pa);不是针对指针或引用做的动态类型转换,编译错误。另外,要注意,转换目标类型和源类型之间不具有多态继承性也会发生编译错误。转换源类型的目标对象非目标类型会发生运行错误。
14.3 完整代码
本案例的完整代码如下所示:#include <iostream> class Base { public: virtual int f1 (void) { std::cout << "Base f1" << std::endl; return 0; } }; class Derived : public Base { public: int f1 (void) { std::cout << "Derived f1" << std::endl; return 0; } }; int main() { Derived d; Base* pa = &d; Derived* pb = dynamic_cast<Derived*> (pa); if (pb == NULL) std::cout << "转换失败!" << std::endl; Base& ra = d; try { Derived& rb = dynamic_cast<Derived&> (ra); } catch (std::bad_cast& ex) { std::cout << "转换失败!" << std::endl; } Derived b = dynamic_cast<Derived> (*pa); return 0; }
15 类型信息
15.1 问题
typeid操作符既可用于类型也可用于对象,用于返回类型信息,即类typeinfo对象的常引用。类typeinfo中含所有一个成员函数name,通过它可以得到类型名。15.2 步骤
实现此案例需要按照如下步骤进行。步骤一:类型信息代码如下:#include <iostream> class A { }; class B : public A { public: virtual void foo (void) { } }; class C : public B { }; int main() { int x; int * px; std::cout << "int is: " << typeid(int).name() << std::endl; std::cout << " x is: " << typeid(x).name() << std::endl; std::cout << " px is: " << typeid(px).name() << std::endl; std::cout << "*px is: " << typeid(*px).name() << std::endl; C c; A& a = c; std::cout << typeid (a).name () << std::endl; B& b = c; std::cout << typeid (b).name () << std::endl; return 0; }上述代码中,以下代码:
int x; int * px; std::cout << "int is: " << typeid(int).name() << std::endl; std::cout << " x is: " << typeid(x).name() << std::endl; std::cout << " px is: " << typeid(px).name() << std::endl; std::cout << "*px is: " << typeid(*px).name() << std::endl;使用typeid获取指定目标的类型信息。如:
std::cout << "int is: " << typeid(int).name() << std::endl;的输出结果为:int is: i。上述代码中,以下代码:
C c; A& a = c; std::cout << typeid (a).name () << std::endl;当typeid作用于基类A类型的引用的目标c时,若基类A中不包含任何虚函数,则该操作符所返回的类型信息由引用A本身的类型决定,即返回的是类A的类名A。上述代码中,以下代码:
B& b = c; std::cout << typeid (b).name () << std::endl;当typeid作用于基类B类型的引用的目标c时,若基类包含至少一个虚函数,即存在多态继承,该操作符所返回的类型信息由该引用的实际目标对象的类型决定,即返回的是类C的类名C。
15.3 完整代码
本案例的完整代码如下所示:#include <iostream> class A { }; class B : public A { public: virtual void foo (void) { } }; class C : public B { }; int main() { int x; int * px; std::cout << "int is: " << typeid(int).name() << std::endl; std::cout << " x is: " << typeid(x).name() << std::endl; std::cout << " px is: " << typeid(px).name() << std::endl; std::cout << "*px is: " << typeid(*px).name() << std::endl; C c; A& a = c; std::cout << typeid (a).name () << std::endl; B& b = c; std::cout << typeid (b).name () << std::endl; return 0; }
相关文章推荐
- Hello ISAPI
- c++宏定义命令
- C++保存json文件(使用jsoncpp库)
- 在Visual Studio上构建C++的GUI框架wxWidgets的开发环境
- C++中cin>> cin.get(char[], int) cin.getline(char[], int) cin.get(char)输入区别
- C语言运算符优先级
- C++作业4-继承和派生1
- c++之精确度
- C++面向对象编程分享08----20160422_李楚煌
- C++函数模板的显示调用与隐式调用
- c++11笔记
- C++的多态
- PAT (Basic Level) Practise (中文)1032. 挖掘机技术哪家强(20)
- Ubuntu下 C++ 创建、删除目录
- C/C++内存管理函数的使用
- c++.dll打印日志到c#界面,使用回调函数
- C++字符串
- 【学习C++】C++ Primer Plus (第六版)第八章编程练习1-7
- C语言中如何将数转化为字符串
- PAT (Basic Level) Practise (中文)1031. 查验身份证(15)