类
- 以类为基础架构和设计被称为面向对象编程(OOP),它与事件驱动、数据库,以及图形用户界面应用程序的需求良好地结合。
- Struct
struct 类的成员默认是公有的。
- Class
默认情况下,成员访问是私有的。 - Union
创建一个数据类型,其成员默认是公有访问的,但在一个联合中,所有成员共享内存中相同的地址。其结果是,相同的位置在不同时间可被用来存储不同类型的数据。
- Struct
关键字 | 描述 |
---|---|
public | 公有访问,(struct关键字创建的数据结构的默认值)。从public:后面起,直到下一个访问级别关键字为止的成员都是公有的,因此可由类的用户访问。注:成员是类的命名空间的一部分,只可以通过该类的一个对象,或说明符号名的作用于(class::的方式)来引用。 |
private | 私有访问,对除类自身的成员函数外都不可见。一个例外是使用friend关键字。 |
protected | 保护访问,不能直接被外部访问。但受保护的成员可以在其子类中访问,无论是直接访问还是间接访问。 |
2. 每个类写一个默认的构造函数,是一个很好的防御性编程。
类名::类名(){
// 初始化
}
3.初始化列表
#include <cstring>
class Dog{
public:
cosnt int gender;
int age;
char name[21];
Dog(int m_f,int a,char *nm):gender(m_f),age(a){
strncpy(name,nm,20);
}
};
- 析构函数不能被const,volatile或static。但是,它可以被声明为virtual。
- 运算符重载
//作为友元的运算符函数
friend 类名 operator + (int n,类名 变量);
//赋值运算符
类名& operator = (const 类名& 参数名){
………………
return *this;
}
// 注意区分
Point pt2=pt1;//调用拷贝构造函数
pt1=pt2;//调用运算符=
//下标运算符
类型& operator [] (const int 索引){
}
通过运算符重载可以是数组越界的可能得到解决。
//两个版本的下标运算符
double& operator [] (const int i);
const double& operator [](const int i) const;
//递增运算和递减运算符
类名& operator++ ();//前缀++point
类名 operator++(int);//后缀point++
//传入和传出转换函数
Point(double newx):x(newx),y(0){}
operator double(){……}//double(类实体)
- using 基类::基类; C++11允许派生类继承基类的所有构造函数。
- 指向派生类的指针不能指向基类的对象。基类的指针可以指向派生类对象可以调用基类地方法,但不能调用子类的方法。
- 虚函数和重载
# include <iostream>
using namespace std;
class Mammal (){
public:
vitural void sound();
};
class Dog::public Mammal(){
public:
void sound();//重载
}
class Cat:public Mammal(){
public:
void sound();//重载
}
Mammal *ptr_to_mammal;
//根据不同指向的不同类型,执行相应类型的方法。因为基类有相同的函数定义。
下面是使用虚函数的一些规则和准则
- 在一般情况下,可能被重载的任何函数都应声明为虚函数
- 当重载一个函数时,类型信息必须与被重载函数的类型信息完全匹配
- 构造函数不能是虚函数,但析构函数可以。
纯虚函数
- virtual 函数声明 =0;
一个具有至少一个纯虚函数的类是一个抽象类(abstract class)。这样的类不能被实例化,但可以声明一个指向这个类的指针。
函数声明 Override;Override关键字表示只有当它重载基类中的一些声明时才允许此声明,否则标记为一个错误的函数,避免命名错误导致系统创建一个新的函数,却没有达到重在的效果。
- C++提供了两种联合:命名联合和匿名联合。
union var_data{
int n;
double x;
char *name[20];
};//在所得的类型中,成员共享同一个内存地址,可以是各种类型的,但每次读取的时候只能包含一个类型的值。
//可以实例化
union{
int n;
double x;
char *name[20];
};//不可以实例化
- 打包的布尔类
#include<iostream>
using namespace std;
//打包布尔类:创建一个动态长度的虚拟布尔数组
//把每个布尔值存储在1位中
class Pack_bool{
private :
int max_n;//位的数目
int nbytes;//所需的字节数
unsigned char* ptr;//指向数据位的指针
public:
Pack_bool(int max_number);//构造函数、
void set_bit(int n);
void clear_bit(int n);
bool get_bit(int n);
void set_all_true(){
for(int i=0;i<nbytes;++i){ptr[i]=0xFF;}
}
void set_all_false(){
for(int i=0;i<nbytes;++i){ptr[i]=0x00;}
}
};
//构造函数:把max除以8向上取整,获取存储字节数。
Pack_bool::Pack_bool(int n){
max_n=n;
nbytes=(max_n+7)/8;//向上取整
ptr=new unsigned char[nbytes];
}
//设置位成员函数
//查找目标位并使用按位或(OR) 来设置为1
void Pack_bool::set_bit(int n){
int i=n/8;
int j=n%8;
ptr[i]=ptr[i] | (0x01<<j);//设置为1
}
//查找目标位并使用按位或(AND) 来设置为0
void Pack_bool::clear_bit(int n){
int i=n/8;
int j=n%8;
ptr[i]=ptr[i] & ~(0x01<<j);//设置为0
}
bool Pack_bool::get_bit(int n){
int i=n/8;
int j=n%8;
return (ptr[i] & (0x01<<j))!=0;
}
int main(){
int sizeOfBits=64;
Pack_bool pb(sizeOfBits);
pb.set_all_false();
for(int i=0;i<sizeOfBits;i+=2){pb.set_bit(i);}
for(int i=0;i<sizeOfBits;++i){cout<<pb.get_bit(i)<<"\t";}
cout<<endl;
cin.ignore();
return 0;
}
- 可变参数模板
声明一个带有可变参数个数的模板的语法如下所示
template<typename... Elements> class tuple;
template<typename Head, typename... Tail>
class tuple<Head, Tail...> : private tuple<Tail...> {
Head head;
public:
/* implementation */
};
template<>
class tuple<> {
/* zero-tuple implementation */
};
在模板参数 Element 左边出现省略号 … ,就是表示 Element 是一个模板参数包(template type parameter pack)。parameter pack(参数包)是新引入 C++ 中的概念,比如在这个例子中,Element 表示是一连串任意的参数打成的一个包。
现在我们知道parameter pack了,怎么在程序中真正具体地去处理打包进来的“任意个数”的参数呢?我原来以为,编译器会提供一些像get_param<1>(Element) 之类的内建的“参数抽取函数”给程序员使用结果不是!!看来我的思路还是太“过程式了”。其实 C++11 用的是 unpack 和类似函数重载似的“模板特化”来抽取参数的。
第1行声明了一个可以对应任意参数的tuple类,第2行到7行声明了这个类的一个部分特化,注意,这就是抽取参数的典型方法了。
其实就是递归调用。
tuple
tuple是个可变参数的类模板:
#include <tuple>
template<typename... _Types>
class tuple;
std::tuple<int, std::string> tu{ 2,"12iop" };
struct Point
{
int x;
int y;
};
void main()
{
std::tuple<int, std::string> t1{ 1,"qwer" };
constexpr std::tuple<int, void*> t2{ 10,nullptr };
std::tuple<int, Point> t3{ 1,{20,89} };
std::tuple<int, char, std::string> t4{ 1,'t',"qwer" };
std::cout << std::get<0>(t1) << std::endl; // 1
constexpr int n2 = std::get<0>(t2);
std::cout << n2 << std::endl; // 10
auto s = std::get<char>(t4);
std::cout << s << std::endl; // t
}
- C 字符串函数
函数名 | 函数作用 |
---|---|
strcat(s1,s2) | 把字符串s2连接到s1的后面 |
strchr(s,ch) | 查找ch字符的位置 |
strcspn(s1s_reject) | 获取直到某个字符的跨度函数,返回从0开始的与s_reject的中的任意字符匹配的第一个字符的位置。 |
strerror(errno) | 返回系统指定的错误号的文本字符串 |
strlen(s) | 此长度是一个直到但不包含终止空字符的字节数。 |
strpbrk(s1,s2) | 返回指向s1内第一个与s2中任何字符匹配的字符的指针。 |
strspn(s1,s_accept) | 返回不含s_accept中的任意字符串的第一个位置 |
strstr(s1,s2) | 返回s2在s1中的第一次出现的指针 |
#include <iostream>
#include <cstring>
using namespace std;
int main(int argc, const char * argv[])
{
char* token,input_ln[80+1];
cin.getline(input_ln,80);
token = strtok(input_ln," ,");
while(token) //存在标记时
{
cout<<token<<endl;//输出此标记
token=strtok(NULL," ,");//寻找下一标记
}
}
这个是线程不安全的
strtok_r(inout," ,",&ptr);//ptr是额外的指针变量
函数名 | 函数作用 |
---|---|
memccpy(目标,源,ch,n) | 直到遇到ch为止,将不超过n的源复制到目标去 |
memchr(缓冲区,ch,n) | 搜索ch |
memcmp(缓冲区1,缓冲区2,n) | 比较 |
memcpy(目标,源,n) | |
memmove(dest,source,n) | 这个可以正确处理内存重叠 |
第13章
C++ I/O
函数名 | 函数说明 |
---|---|
istream对象.getline(cstr,n[,delim_ch=’\n’]) | 把一行输入读取到一个C字符串(cstr),方括号表示第三个参数是可选的。默认是换行符,作用是读取到指定的分隔符的字符串 |
getline(istream对象,str对象[,delim_ch=’\n’]) | 同上,这里是给str对象。 |
graph TB
ios类-->ostream
ios类-->istream
ostream-->ofstream
istream-->ifstream
流对象:控制符及标志
cout<<hex;十六进制
cout<<dec;十进制
cout<<showbase<<endl;显示前缀 0x(hex)