1.总体目录框架
2.类域
(1)全局作用域
在函数和其他类定义的外部定义的类称为全局类,绝大多数的 C++ 类是定义在该作用域中,我们在前面定义的所有类都是在全局作用域中,全局类具有全局作用域
(2)类作用域
一个类可以定义在另一类的定义中,这是所谓嵌套类或者内部类
①如果A的访问权限是public,则A的作用域可认为和B的作用域相同
②如果A的访问权限是private,则只能在类内使用类名创建该类的对象,无法在外部创建A类的对象
③内部类(嵌套类):
1)应用 pimpl :PIMPL(Private Implementation 或Pointer to >Implementation)是通过一个私有的成员指针,将指针所指向的类的内部实现数据进>行隐藏
设计模式有如下优点:
1.提高编译速度;
2. 实现信息隐藏;
3. 减小编译依赖,可以用最小的代价平滑的升级库文件;
4. 接口与实现进行解耦;
5. 移动语义友好。2)单例模式的自动释放 四种方式
①友元形式
②嵌套类 + 静态对象(饱汉(懒汉)模式)
③atexit方式进行(饿汉模式)
④atexit+pthread_once形式,平台相关(多线程安全,用到pthread_once())
3)内存泄漏的检测工具:valgrind
使用方法:
valgrind --tool=memcheck --leak-check=full ./执行文件
(3)块作用域
例如可以存在在test()函数块中,很少见
(4)具体代码
作用域与可见域:如果没有同名的话,变量的作用域与可见域是一样的。
1)补充作用域总结打印
2)补充类作用域(内部类)
3)设计模式之Pimpl实现
4)单例模式的自动释放 四种方式
①友元形式
②嵌套类 + 静态对象(饱汉(懒汉)模式)
③atexit方式进行(饿汉模式)
④atexit+pthread_once形式,平台相关(多线程安全)
1)补充作用域总结打印
#include <iostream>
using std::cout;
using std::endl;
int x = 1;
namespace wd
{
int x = 10;
class Test
{
public:
Test(int value)
: x(value)
{
}
void print(int x) const
{
cout << "形参x = " << x << endl; //300
cout << "数据成员x = " << this->x << endl; //400
cout << "数据成员x = " << Test::x << endl; //400
cout << "命名空间中的x = " << wd::x << endl; //10
cout << "全局的x = " << ::x << endl; //1
}
private:
int x;
};
}//end of namespace wd
int main(int argc, char **argv)
{
int value = 300;
wd::Test tst(400);
tst.print(value);
return 0;
}
2)补充类作用域(内部类)
#include <iostream>
using std::cout;
using std::endl;
class Line
{
public:
Line(int x1, int y1, int x2, int y2)
: _pt1(x1, y1)//类对象成员需要显示进行初始化,否则就是默认值
, _pt2(x2, y2)
{
cout << "Line(int, int, int,int)" << endl;
}
void printLine()
{
_pt1.print();
_pt2.print();
}
~Line()
{
cout << "~Line()" << endl;
}
private:
class Point
{
public:
Point(int ix = 0, int iy = 0)
: _ix(ix)
, _iy(iy)
{
cout << "Point(int = 0, int = 0)" << endl;
}
void print()
{
cout << "(" << _ix << ", "
<< _iy << ")" << endl;
}
~Point()
{
cout << "~Point()" << endl;
}
private:
int _ix;
int _iy;
};
private:
Point _pt1;//类对象成员(子对象)
Point _pt2;
};
int main(int argc, char **argv)
{
Line line(1, 2, 3, 4);
line.printLine();
//要想直接使用Point类的话,外面不能直接访问,下面是错误的
/* Line::Point pt1(1, 3);//error */
return 0;
}
3)设计模式之Pimpl实现
①头文件:point.h
②构建Line类的实现 point.cc
③测试 testpoint.cc
//point.h
#ifndef __POINT_H__
#define __POINT_H__
class Line
{
public:
Line(int x1, int y1, int x2, int y2);
void printLine();
~Line();
class PointPimpl;
private:
PointPimpl *_pimpl;
};
#endif
//point.cc
#include "Point.h"
#include <iostream>
using std::cout;
using std::endl;
class Line::PointPimpl
{
public:
PointPimpl(int x1, int y1, int x2, int y2)
: _pt1(x1, y1)//类对象成员需要显示进行初始化,否则就是默认值
, _pt2(x2, y2)
{
cout << "PointPimpl(int, int, int,int)" << endl;
}
void printPimpl()
{
_pt1.print();
_pt2.print();
}
~PointPimpl()
{
cout << "~PointPimpl()" << endl;
}
private:
class Point
{
public:
Point(int ix = 0, int iy = 0)
: _ix(ix)
, _iy(iy)
{
cout << "Point(int = 0, int = 0)" << endl;
}
void print()
{
cout << "(" << _ix << ", "
<< _iy << ")" << endl;
}
~Point()
{
cout << "~Point()" << endl;
}
private:
int _ix;
int _iy;
};
private:
Point _pt1;//类对象成员(子对象)
Point _pt2;
};
Line::Line(int x1, int y1, int x2, int y2)
: _pimpl(new PointPimpl(x1, y1, x2, y2))
{
cout << "Line(int, int, int, int)" << endl;
}
void Line::printLine()
{
_pimpl->printPimpl();
}
Line::~Line()
{
cout << "~Line()" << endl;
if(_pimpl)
{
delete _pimpl;
_pimpl = nullptr;
}
}
#include "Point.h"
#include <iostream>
using std::cout;
using std::endl;
int main(int argc, char **argv)
{
Line line(1, 2, 3, 4);
line.printLine();
return 0;
}
4)四种单例类模式
①友元形式
②嵌套类 + 静态对象(饱汉(懒汉)模式)
③atexit方式进行(饿汉模式)
④atexit+pthread_once形式,平台相关(多线程安全)
//①友元形式实现单例类
#include <iostream>
using std::cout;
using std::endl;
//1、使用友元
class AutoRelease;//类的前向声明
class Singleton
{
friend class AutoRelease;
public:
//类中的static变量会保证全局唯一,多个实例共享一个static变量,如果该static变量已经初始化过了,不会再次初始化!
static Singleton *getInstance()
{
if(nullptr == _pInstance)
{
_pInstance = new Singleton();
}
return _pInstance;
}
static void destroy()
{
if(_pInstance)
{
delete _pInstance;
_pInstance = nullptr;
}
}
private:
Singleton()
{
cout << "Singleton()" << endl;
}
~Singleton()
{
cout << "~Singleton()" << endl;
}
private:
static Singleton *_pInstance;
};
Singleton *Singleton::_pInstance = nullptr;
class AutoRelease
{
public:
AutoRelease()
{
cout << "AutoRelease()" << endl;
}
~AutoRelease()
{
cout << "~AutoRelease()" << endl;
if(Singleton::_pInstance)
{
delete Singleton::_pInstance;
Singleton::_pInstance = nullptr;
}
}
};
int main(int argc, char **argv)
{
Singleton *ps1 = Singleton::getInstance();
AutoRelease ar;//栈对象
/* Singleton::destroy(); */
return 0;
}
//②嵌套类 + 静态对象(饱汉(懒汉)模式)
#include <iostream>
using std::cout;
using std::endl;
//2、内部类 + 静态数据成员
class Singleton
{
public:
static Singleton *getInstance()
{
if(nullptr == _pInstance)
{
_pInstance = new Singleton();
}
return _pInstance;
}
static void destroy()
{
if(_pInstance)
{
delete _pInstance;
_pInstance = nullptr;
}
}
private:
Singleton()
{
cout << "Singleton()" << endl;
}
~Singleton()
{
cout << "~Singleton()" << endl;
}
private:
class AutoRelease
{
public:
AutoRelease()
{
cout << "AutoRelease()" << endl;
}
~AutoRelease()
{
cout << "~AutoRelease()" << endl;
if(_pInstance)
{
delete _pInstance;
_pInstance = nullptr;
}
}
};
private:
static Singleton *_pInstance;
static AutoRelease _auto;
};
Singleton *Singleton::_pInstance = nullptr;
Singleton::AutoRelease Singleton::_auto;
int main(int argc, char **argv)
{
Singleton *ps1 = Singleton::getInstance();
/* Singleton::AutoRelease ar;//栈对象//error */
/* Singleton::destroy(); */
return 0;
}
//③atexit + 饿汉模式
#include <stdlib.h>
#include <iostream>
using std::cout;
using std::endl;
//3、atexit + 饿汉模式
class Singleton
{
public:
static Singleton *getInstance()
{
//在多线程环境下不安全
if(nullptr == _pInstance)
{
_pInstance = new Singleton();
atexit(destroy);
}
return _pInstance;
}
static void destroy()
{
if(_pInstance)
{
delete _pInstance;
_pInstance = nullptr;
}
}
private:
Singleton()
{
cout << "Singleton()" << endl;
/* atexit(destroy); */
}
~Singleton()
{
cout << "~Singleton()" << endl;
}
private:
static Singleton *_pInstance;
};
/* Singleton *Singleton::_pInstance = nullptr;//饱汉(懒汉)模式 */
Singleton *Singleton::_pInstance = getInstance();//饿汉模式
int main(int argc, char **argv)
{
Singleton *ps1 = Singleton::getInstance();
Singleton *ps2 = Singleton::getInstance();
/* Singleton::AutoRelease ar;//栈对象//error */
/* Singleton::destroy(); */
return 0;
}
//④atexit+pthread_once形式,平台相关
//编译加上-lpthread
//得加头文件pthread.h
#include <pthread.h>
#include <stdlib.h>
#include <iostream>
using std::cout;
using std::endl;
//4、pthread_once + atexit(平台相关)
class Singleton
{
public:
static Singleton *getInstance()
{
pthread_once(&_once, init);
return _pInstance;
}
static void init()
{
_pInstance = new Singleton();
atexit(destroy);
}
static void destroy()
{
if(_pInstance)
{
delete _pInstance;
_pInstance = nullptr;
}
}
private:
Singleton()
{
cout << "Singleton()" << endl;
/* atexit(destroy); */
}
~Singleton()
{
cout << "~Singleton()" << endl;
}
private:
static Singleton *_pInstance;
static pthread_once_t _once;
};
Singleton *Singleton::_pInstance = nullptr;//饱汉(懒汉)模式
/* Singleton *Singleton::_pInstance = getInstance();//饿汉模式 */
//pthread_once初始化
pthread_once_t Singleton::_once = PTHREAD_ONCE_INIT;
int main(int argc, char **argv)
{
Singleton *ps1 = Singleton::getInstance();
Singleton *ps2 = Singleton::getInstance();
/* Singleton::AutoRelease ar;//栈对象//error */
/* Singleton::destroy(); */
return 0;
}
3.std::string底层实现
(1)string三种实现版本
1)深拷贝(浅拷贝
2)写时复制 浅拷贝 + 引用计数
3)短字符串优化 当字符串的长度小于等于15字节时候,放栈上;当字符串长度大于16字节的时候,就放在堆上
(2)查看ubuntu版本信息
lsb_release -a
或
cat /proc/version
14.04string有8个字节,18.04有32个字节
18.04用的不是写时复制,而是短字符串优化
(3)引用计数放哪里?
1、全局静态不行
2、栈不行, const String &rhs,const是常量不能修改
3、文字常量区 程序代码 只读段, 引用计数会进行修改,也不行
4、只能放在堆上,其实在堆上任何位置都可以,只是为了好获取将将引用计数与数据放在一起,并且最好在数据前面,这样当数据变化的时候不会移动引用计数的位置
引用计数相关代码
//cowstring.cc
#include <string.h>
#include <iostream>
using std::cout;
using std::endl;
class String
{
public:
//String s1;
String()
//5表示4个字节的引用技术和1一个字节的'\0'
//4表示指针从引用计数的位置移动到字符串开始的位置
: _pstr(new char[5]() + 4)
{
cout << "String()" << endl;
//(_pstr-4)表示指向引用计数
//(int *)表示强转成Int类型的指针
//要给里面引用计数赋值,所以要用*解引用
//*(int *)(_pstr-4)=1
initRefCount();
}
//String s1("hello");
String(const char *pstr)
: _pstr(new char[strlen(pstr) + 5]() + 4)
{
cout << "String(const char *)" << endl;
strcpy(_pstr, pstr);
//*(int *)(_pstr-4)=1
initRefCount();
}
//String s2 = s1
String(const String &rhs)
: _pstr(rhs._pstr)
{
cout << "String(const String &)" << endl;
//++*(int *)(_pstr-4);
increaseRefCount();
}
//String s3("world");
//s3 = s1;
//赋值运算符函数
String &operator=(const String &rhs)
{
cout << "String &operator=(const String &)" << endl;
if(this != &rhs)//1、自复制
{
release();//2、释放左操作数
//s3和s1指向同一片空间
_pstr = rhs._pstr;//3、浅拷贝
//--*(int *)(_pstr-4);
increaseRefCount();
}
return *this;//4、返回*this
}
//s3[0] = 'H';
//写时复制
char &operator[](size_t idx)
{
if(idx < size())
{
if(getRefCount() > 1)//是共享,共享次数较多
{
//先申请堆空间
char *ptmp = new char[strlen(_pstr) + 5]() + 4;
//然后把数据靠过来
strcpy(ptmp, _pstr);
//s3要和s2、s1脱离了,把引用计数--
decreaseRefCount();
//把ptmp赋给_pstr
_pstr = ptmp;
//初始化引用计数为1
initRefCount();
}
return _pstr[idx];
}
else
{
static char nullchar = '\0';
return nullchar;
}
}
~String()
{
cout << "~String()" << endl;
release();
}
const char *c_str() const
{
return _pstr;
}
int getRefCount() const
{
return *(int *)(_pstr - 4);
}
size_t size() const
{
return strlen(_pstr);
}
void initRefCount()
{
*(int *)(_pstr - 4) = 1;
}
void increaseRefCount()
{
++*(int *)(_pstr - 4);
}
void decreaseRefCount()
{
--*(int *)(_pstr - 4);
}
void release()
{
decreaseRefCount();
if(0 == getRefCount())
{
delete [] (_pstr - 4);
}
}
friend std::ostream &operator<<(std::ostream &os, const String &rhs);
private:
char *_pstr;
};
//输出流运算符
std::ostream &operator<<(std::ostream &os, const String &rhs)
{
if(rhs._pstr)
{
os << rhs._pstr;
}
return os;
}
void test()
{
String s1("hello");
cout << "s1 = " << s1 << endl;
//看s1的地址
printf("s1's address: %p\n", s1.c_str());
//打印引用计数
printf("s1's RefCount = %d\n", s1.getRefCount());
cout << endl;
String s2 = s1;
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
printf("s1's address: %p\n", s1.c_str());
printf("s2's address: %p\n", s2.c_str());
printf("s1's RefCount = %d\n", s1.getRefCount());
printf("s2's RefCount = %d\n", s2.getRefCount());
cout << endl;
String s3("world");
cout << "s3 = " << s3 << endl;
printf("s3's address: %p\n", s3.c_str());
printf("s3's RefCount = %d\n", s3.getRefCount());
cout << endl << "执行s3 = s1操作" << endl;
s3 = s1;
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
cout << "s3 = " << s3 << endl;
printf("s1's address: %p\n", s1.c_str());
printf("s2's address: %p\n", s2.c_str());
printf("s3's address: %p\n", s3.c_str());
printf("s1's RefCount = %d\n", s1.getRefCount());
printf("s2's RefCount = %d\n", s2.getRefCount());
printf("s3's RefCount = %d\n", s3.getRefCount());
cout << endl << "对s3[0] = \'H\'" << endl;
//对s3进行写时复制
s3[0] = 'H';
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
cout << "s3 = " << s3 << endl;
printf("s1's address: %p\n", s1.c_str());
printf("s2's address: %p\n", s2.c_str());
printf("s3's address: %p\n", s3.c_str());
printf("s1's RefCount = %d\n", s1.getRefCount());
printf("s2's RefCount = %d\n", s2.getRefCount());
printf("s3's RefCount = %d\n", s3.getRefCount());
//需要区分读和写,现在写没问题,读有bug
cout << endl << "对s1[0]读操作的时候" << endl;
cout << "s1[0] = " << s1[0] << endl;
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
cout << "s3 = " << s3 << endl;
printf("s1's address: %p\n", s1.c_str());
printf("s2's address: %p\n", s2.c_str());
printf("s3's address: %p\n", s3.c_str());
printf("s1's RefCount = %d\n", s1.getRefCount());
printf("s2's RefCount = %d\n", s2.getRefCount());
printf("s3's RefCount = %d\n", s3.getRefCount());
}
int main(int argc, char **argv)
{
test();
return 0;
}