huangfu Blog
Love Leanote!
Toggle navigation
huangfu Blog
主页
About Me
归档
标签
06拷贝构造/静态成员/单例模式
2017-02-11 14:05:30
137
0
0
tarena
#拷贝构造函数 **1. 概念** 以复制的形式来构建对象 (使用一个已经存在的对象以复制的形式创建另外一个不存在的对象) 拷贝构造函数原型: class A { public: A(const A& a) { } }; **2. 拷贝构造调用时机** 以一个存在的对象去创建另外一个不存在的对象的时候 * 把一个对象传入一个`非引用类型的值i`参数时 * 把一个对象作为函数的返回值时 例子代码: #include <iostream> using namespace std; class A { public: int x; int y; A(int x,int y):x(x),y(y) { } /* 创建一个拷贝构造函数*/ A(const A& a) { x = a.x; y = a.y; } }; /* 调用此函数会调用拷贝构造*/ void testA(A a) { } /* 调用此函数不会调用拷贝构造*/ void testA(A& a) { } /* 调用此函数会调用拷贝构造*/ A getA(A& a) { } int main() { A a(100,200); A b = a; // 调用拷贝构造 testA(a); /* 如果不接受返回值,则拷贝到临时区 如果接受返回值,则拷贝到对应类所在内存中*/ getA(a); // 调用拷贝构造 A c = getA(a); // 调用拷贝构造,如果返回值是引用也会调用拷贝构造 } **扩展** #includ <iostream> using namespace std; class A { public: int x; A() { x = 10; cout << "A()" << endl; } A(const A& a) { cout << "A(const A&)" << endl; } }; A foo() { A a; a.x = 100; return a; } int main() { /* 以下调用由于编译器优化不会调用拷贝构造,并且只会调用一次构造函数*/ /* 编译器检查到返回的是局部对象,编译器优化成直接在临时区或对象b所在内存中创建一个对象*/ A b = foo(); // A() cout << b.x << endl; // 100 } 因此C++又增加一个知识点来`简化编程`,叫做`匿名对象` A foo() { return A; //如果需要传参 return A(100,200) } **3. 什么时候需要自定义拷贝?** 如果不给类型提供拷贝构造,则编译器会自动提供一个默认的拷贝构造函数 `默认的`拷贝函数完成`逐字节拷贝(浅拷贝)` 浅拷贝带来的问题: 类1 x(10) y(5) *p(指向堆区的指针0x1234) 类2 x(10) y(5) *p(指向堆区的指针0x1234) 这样指向堆区的内存共用了,如果在析构函数释放,则很容易造成double free 深拷贝例子代码 #includ <iostream> using namespace std; class Array { int len; int size; int* datas; public: Array(int len = 3) :len(len),size(0) { datas = new int[len]; } Array(const Array& a) { len = a.len; size = a.size; datas = new int[len]; for(int i = 0; i < size; i++) datas[i] = a.datas[i]; } ~Array() { delete[] datas; } void push_back(int d) { if(size >= len) expend(); datas[size++] = d; } void expend() { len = 2*len + i; int *temp = datas; datas = new int[len]; for(int i = 0; i < size; i++) datas[i] = temp[i]; delete[] temp; } void show() { cout << "[ "; for(int i = 0; i < size; i++) cout << datas[i] << ' '; cout << "]" << endl; } }; int main() { Array array(5); for(int i = 0; i < 20; i++) array.push_back(i); array.show(); Array Arrb = Array; arrb.show(); /*输出结果: [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19] [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19] */ } #静态成员 **1. 静态成员函数** 不需要对象就可以直接调用的函数(通过对象也能调用) > 类型名::静态成员函数名(); static成员函数`无法访问普通成员变量或函数`,因为编译器没有传this指针 但普通函数可以访问静态函数或成员 **2. 静态成员变量** 静态成员变量属于`类型级的变量`,不属于对象级的变量 静态成员变量一般用来处理共享的数据,这个数据属于整个类型,内存中只有一份 静态成员变量`必须在类外进行初始化动作` > 静态成员变量类型 类名::静成员变量; 以上表达式初始化`基本类型初始化成0,类类型调用无参构造` > 静态成员变量类型 类名::静成员变量 = 值; > 静态成员变量类型 类名::静成员变量(值); **3. 例子代码** #include <iostream> using namespace std; class Person { string name; int age; static pcount; public: Person(string name="", int age = 1) { this->name = name; this->age = age; pcount++; cout << "欢迎" << name << endl; cout << "现在的人数是:" << pcount << endl; } void show() { cout << "我是" << name << "年龄是" << age << endl; cout << "现在的人数是:" << pcount << endl; } ~Person() { cout << "欢送" << name << endl; pcount--; cout << "现在的人数是:" << pcount << endl; } }; int Persion::pcount; //int Persion::pcount = 0; void foo() { Person p1("奥巴马",30); Person p2("普京",20); } int main() { foo() Person p3("习近平", 40); } #单例模式 **1. 概念** 一个应用中,这个类型的对象只有一个 **2. 涉及到的知识点** 构造 拷贝构造 权限 引用 静态 **3. 饿汉式单例模式例子代码** 饿汉式单例模式只要加载进程时就会创建,不管你用不用,总会创建一个,优点是线程安全 #include <iostream> using namespace std; class Singleton { static Singleton singleton; Singleton() { } Singleton(const Singleton& s) { } public: static Singleton& getInstance() { return singleton; } }; Singleton Singleton::singleton; int main() { Singleton& siga = Singleton::getInstance(); Singleton& sigb = Singleton::getInstance(); cout << &siga << '/' << &sigb << endl; // siga 和 sigb地址相同 } /* 程序解读: 首先在Singleton类里创建一个static Singleton类类型的静态成员变量 这里创建静态成员变量的目的有两点: 1. 静态成员变量才有资格创建与所在类相同类型的类变量, 普通变量不允许类型于所在类类型一样 2. 静态成员变量可以在类外进行初始化,重要的是可以调用私有的构造函数 接下来为了防止创建多个对象,要对构造函数权限私有化 接下来进行初始化静态成员变量,这样只要进程一运行,就会创建一个唯一对象,并且该对象没有名字 那么如何条用该对象呢?? 解决办法就是创建一个static的并且权限为公开的API staic Singleton& getInstance() { return sig; } 注意返回值要用引用,否则该API会调用拷贝构造 最后在主函数创建一个Singleton引用类型变量来接受API返回值就可以了. 尽管该API可以调用多次,单每次返回的引用(地址)都是相同的 */ **4. 懒汉式单例模式例子代码** 懒汉式单例模式用则创建,不用则不会创建,缺点是线程不安全 #include <iostream> using namespace std; class Singleton { static Singleton* sig; Singleton() { } Singleton(const Singleton& s) { } public: static Singleton& getInstance() { if(sig == NULL) sig = new Singleton; return *sig; } }; Singleton* Singleton::sig = NULL; int main() { Singleton& siga = Singleton::getInstance(); Singleton& sigb = Singleton::getInstance(); cout << &siga << '/' << &sigb << endl; }
上一篇:
07成员指针/运算符重载/友元函数/输入输出运算符重载
下一篇:
05this指针/const对象和const函数/析构函数
0
赞
137 人读过
新浪微博
微信
腾讯微博
QQ空间
人人网
提交评论
立即登录
, 发表评论.
没有帐号?
立即注册
0
条评论
More...
文档导航
没有帐号? 立即注册