C++无法被继承的类实现以及单例模式的类的实现
2017-05-04 01:32
405 查看
无法被继承的类的实现
思路
构造函数是类的私有成员函数,同时在共有成员函数里,声明创建该类的实例的函数。以及释放该类的析构函数。范例
#include<iostream> using namespace std; class A { public: static A * Construct(int n) { A *pa = new A; pa->num = n; cout << "num is:" << pa->num << endl; return pa; } static void Destruct(A * pIntance) { delete pIntance; pIntance = NULL; } private: A(){} ~A(){} public: int num; }; class B:public A//如果后面声明一个B的实例,则报错 { }; void main() { A *f = A::Construct(9); cout << f->num << endl; A::Destruct(f); // B b;//error error: ‘A::A()’ is private }
上面这个类不可以实现在栈上创建对象。也就是说,仅仅只可以在堆上构建任何的一个对象,而在栈上就无能为力了。
私有的构造函数极大的局限性就这样一览无余了。(其实,上面类设计即是一种只可以创建堆对象,不可以创建栈对象的情况。
i
a在栈上建立一个类的对象,需要使用下面的方法:
#include<iostream> using namespace std; template <typename T> class Base { friend T; private: Base() {} ~Base() {} }; class Finalclass : virtual public Base<Finalclass> { public: Finalclass() {} ~Finalclass() {} }; class TestClass : public Finalclass { }; int main() { Finalclass* p = new Finalclass; // 堆上对象 Finalclass fs; // 栈上对象 // TestClass tc; // 基类构造函数私有,不可以被继承。因此不可以创建栈上对象。 return 0; }
当派生类TestClass在构造对象时,因为是虚继承,所以派生类TestClass的构造函数会直接去调用Base基类的构造函数,而Base的构造函数是私有的。编译错误!
单例模式
#include <iostream> using namespace std; class CSingleton { private: CSingleton() //构造函数是私有的 { } static CSingleton *m_pInstance; public: static CSingleton * GetInstance() { if(m_pInstance == NULL) //判断是否第一次调用 m_pInstance = new CSingleton(); return m_pInstance; } }; CSingleton *CSingleton ::m_pInstance=NULL;//一定要初始化 int main() { CSingleton* p0 = CSingleton :: GetInstance(); CSingleton* p1 = CSingleton :: GetInstance(); CSingleton* p2 = p1->GetInstance(); CSingleton & ref = * CSingleton :: GetInstance(); cout<<p0<<endl;//0xfcd010 cout<<p1<<endl;//0xfcd010 cout<<p2<<endl;//0xfcd010 cout<<&ref<<endl;//0xfcd010 return 0; }
另外测试
#include<iostream> using namespace std; class CSingleton { private: CSingleton() { cout<<"调用Csingleton 的构造函数"<<endl;} static CSingleton *m_pInstance; class CGarbo { public: ~CGarbo() { cout<<"调用CGarbo的析构函数"<<endl; if(CSingleton::m_pInstance) { delete CSingleton::m_pInstance; cout<<"delete CSingleton::m_pInstance;"<<endl; } } }; static CGarbo Garbo; public: static CSingleton * GetInstance() { cout<<"调用GetInstance"<<endl; if(m_pInstance == NULL) { cout<<"m_pInstance == NULL"<<endl; m_pInstance = new CSingleton(); } return m_pInstance; } }; CSingleton* CSingleton ::m_pInstance=NULL; CSingleton::CGarbo CSingleton::Garbo; class aclass{ public: int c; static int a; static void fun(){cout<<a<<endl;}//静态函数只能访问静态成员 void fun2(){cout<<a<<endl;} }; int aclass::a=0; //初始化 int main() { CSingleton* p1 = CSingleton :: GetInstance(); CSingleton* p2 = p1->GetInstance(); CSingleton & ref = * CSingleton :: GetInstance(); aclass A; A.a++; cout<<A.a<<endl; aclass B; B.a++; cout<<B.a<<endl; cout<<aclass::a<<endl; B.fun(); A.fun2(); return 0; } //输出: 调用GetInstance m_pInstance == NULL 调用Csingleton 的构造函数 调用GetInstance 调用GetInstance 调用CGarbo的析构函数 delete CSingleton::m_pInstance; 1 2 2 2 2 /对于单例函数的析构函数写法: 第一种想法: 怎么在程序结束的时候对其释放尼。基本的思路是定义一个内部类,然后再类内部定义一个内部类的对象,这样在程序结束的时候,在释放内部类对象的时候会调用内部类的析构函数,我们就可以将所有的释放操作放在内部类的析构函数中进行。
z注意得加上这一句,初始化Garbo。
CSingleton::CGarbo CSingleton::Garbo;
第二种想法:
单例模式另外两个写法:
http://www.2cto.com/kf/201403/283007.html补充一点静态成员函数知识
1.静态成员函数的地址可用普通函数指针储存,而普通成员函数地址需要用 类成员函数指针来储存。举例如下:class base{
static int func1();
int func2();
};
int (*pf1)()=&base::func1;//普通的函数指针
int (base::*pf2)()=&base::func2;//成员函数指针
2.静态成员函数不可以调用类的非静态成员。因为静态成员函数不含this指针。
3.静态成员函数不可以同时声明为 virtual、const、volatile函数。举例如下:
class base{
virtual static void func1();//错误
static void func2() const;//错误
static void func3() volatile;//错误
};
最后要说的一点是,静态成员是可以独立访问的,也就是说,无须创建任何对象实例就可以访问。
e为什么静态成员函数只能只能访问静态成员?
和静态数据成员一样,静态成员函数是类的一部分,而不是对象的一部分。如果要在类外调用公用的静态成员函数,要用类名和域运算符“∷”。如 Box∷volume( ); 实际上也允许通过对象名调用静态成员函数,如 a.volume( ); 但这并不意味着此函数是属于对象a的,而只是用a的类型而已。 静态成员函数的作用是为了能处理静态数据成员。 可以说,静态成员函数与非静态成员函数的根本区别是:非静态成员函数有this指针,静态成员函数并不属于某一对象,它与任何对象都无关,静态成员函数没有this指针。由此决定了静态成员函数不能访问本类中的非静态成员。 在C++程序中,静态成员函数主要用来访问静态数据成员,而不访问非静态成员。假如在一个静态成员函数中有以下语句: cout << height<< endl; //若height已声明为static,则引用本类中的静态成员,合法 cout << width<< endl; //若width是非静态数据成员,不合法 但是,并不是绝对不能引用本类中的非静态成员,只是不能进行默认访问,因为无法知道应该去找哪个对象。如果一定要引用本类的非静态成员,应该加对象名和成员运算符“.”。如 cout<< a.width << endl; //引用本类对象a中的非静态成员。
类的静态成员(变量和方法)属于类本身,在类加载的时候就会分配内存,可以通过类名直接去访问;非静态成员(变量和方法)属于类的对象,所以只有在类的对象产生(创建类的实例)时才会分配内存,然后通过类的对象(实例)去访问。
在一个类的静态成员中去访问其非静态成员之所以会出错是因为在类的非静态成员不存在的时候类的静态成员就已经存在了,访问一个内存中不存在的东西当然会出错:class CA{private:int a; //非静态成员,创建类的实例时分配内存,类的不同实例对应不同的内存区域
相关文章推荐
- 设计模式之代理模式 c++实现以及详解
- VMware虚拟机偶尔无法实现拖曳功能的解决办法以及Vmware虚拟机NAT连接模式进行端口转发
- C语言模式实现C++继承和多态
- 模拟继承和多态--C语言模式实现C++继承和多态
- 类成员C++笔记六:static类成员总结,以及利用C++类static成员实现单例模式
- 由前序遍历和中序遍历重建二叉树和C语言模式实现C++继承和多态——题集(十四)
- C语言模式实现C++继承和多态
- C语言模式实现C++继承和多态的实例代码
- c++虚函数实现机制以及类继承中的内存分布
- C++中的虚继承,以及利用虚继承实现的sealed类
- 三种工厂模式的分析以及C++实现
- 三种工厂模式的分析以及C++实现
- 三种工厂模式的分析以及C++实现
- 设计模式之单例模式 c++实现以及详解
- Javascript乱弹设计模式系列(0) - 面向对象基础以及接口和继承类的实现
- VMware虚拟机偶尔无法实现拖曳功能的解决办法以及Vmware虚拟机NAT连接模式进行端口转发
- C++笔记六:static类成员总结,以及利用C++类static成员实现单例模式
- C语言模式实现C++继承和多态
- 单例模式简介以及C++版本的实现
- 三种工厂模式的分析以及C++实现