OC++

作者: Trigger_o | 来源:发表于2022-08-16 19:34 被阅读0次

一.回忆一下C++

using可以代替typedef

using intvec = std::vector<int>;

const int& fun(int& a); //修饰返回值
int& fun(const int& a); //修饰形参
int& fun(int& a) const{} //const成员函数

char实质是一个字节的整形
signed表示有符号,unsigned表示无符号
修饰符 signed、unsigned、long 和 short 可应用于整型,signed 和 unsigned 可应用于字符型,long 可应用于双精度型。
修饰符 signed 和 unsigned 也可以作为 long 或 short 修饰符的前缀。例如:unsigned long int。
也可以只写单词 unsigned、short 或 long,int 是隐含的.

修饰符 volatile 告诉编译器不需要优化volatile声明的变量,让程序可以直接从内存中读取变量。对于一般的变量编译器会对变量进行优化,将内存中的变量值放在寄存器中以加快读写效率。

由 restrict 修饰的指针是唯一一种访问它所指向的对象的方式

extern 用于声明一个全局变量或函数,用以支持在当前文件(或者引用了这个文件的其他文件)中可以使用,而变量或者函数真正的定义可以在任何地方.

使用 thread_local 说明符声明的变量仅可在它在其上创建的线程上访问。 变量在创建线程时创建,并在销毁线程时销毁。 每个线程都有其自己的变量副本。

thread_local int x;  // 命名空间下的全局变量
class X
{
    static thread_local std::string s; // 类的static成员变量
};
static thread_local std::string X::s;  // X::s 是需要定义的
 
void foo()
{
    thread_local std::vector<int> v;  // 本地变量

^ 异或运算
~ 按位取反,包括符号位
<< 左移若干位
>>右移若干位

A = 0011 1100
// ~A : 1100 0011
//A << 2 : 1111 0000
//A >> 2 : 0000 1111

位运算也支持和赋值结合

A <<= 2

lambda表达式 capture->return-type{body}
[] // 沒有定义任何变量。使用未定义变量会引发错误。
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&] // 任何被使用到的外部变量都隐式地以引用方式加以引用。
[=] // 任何被使用到的外部变量都隐式地以传值方式加以引用。
[&, x] // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。

[](int x, int y){ return x < y ; }
[](int x, int y) -> int { int z = x + y; return z + x; }
[this]() { this->someFunc(); }();

引用经常被理解为地址,与指针的区别:
不存在空引用。引用必须连接到一块合法的内存。
一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
引用必须在创建时被初始化。指针可以在任何时间被初始化。

//这个函数需要一个int型的引用为参数
void swap(int& x);

int    i;
//创建了一个int型引用
int&    r = i;

//返回一个double类型引用
double& setValues(int i)

typedef定义时,Books可以取代struct Books

typedef struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
}Books;

变量和指针访问结构体或对象成员的区别:变量用.指针用->

Books Book1; //定义结构体
struct Books *struct_pointer; //定义指针
struct_pointer = &Book1; //指针赋值
struct_pointer->title; //指针访问结构体成员

范围解析运算符 ::
用于在类的定义之外添加成员函数

//表示给Box添加一个成员函数
double Box::getVolume(void)
{
    return length * breadth * height;
}

构造函数的初始化列表

Line::Line( double len): length(len)
{
   //do something
}

//length是Line的成员变量,这个函数其实就相当于下面
Line::Line( double len)
{
    length = len;
    //do something
}

析构函数

Line::~Line(void)
{
  // do something
}

声明函数,可以先不提供实现;
其中Line( const Line &obj);是拷贝构造函数,相当于objc的copy

class Line
{
   public:
      Line( int len );             // 简单的构造函数
      Line( const Line &obj);      // 拷贝构造函数
      ~Line();                     // 析构函数

};

使用friend声明友元函数或友元类,他们可以访问类的private和protected成员
注意:1.printWidth() 不是任何类的成员函数
2.友元函数不能使用this

class Box
{
   double width;
public:
   friend void printWidth( Box box ); //声明友元函数
   void setWidth( double wid );
};

void printWidth( Box box )
{
   /* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
   cout << "Width of box : " << box.width <<endl;
}


//声明友元类
class Tex
{
   friend class Box;
   Int num;
};

使用inline声明内联函数,如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方,类似于宏替换,以空间换时间.
1.在内联函数内不允许使用循环语句和开关语句;
2.内联函数的定义必须出现在内联函数第一次调用之前;
3.在类定义的{}内定义的函数默认就是内联函数。

//这是一个全局的内联函数
inline int Max(int x, int y)
{
   return (x > y)? x : y;
}

在C++中重载指的是同样的函数名有着不一样的参数列表和返回值

void print(int i) {
        cout << "整数为: " << i << endl;
      }
 
      void print(double  f) {
        cout << "浮点数为: " << f << endl;
      }
 
      void print(char c[]) {
        cout << "字符串为: " << c << endl;
      }

用virtual声明虚函数,只有virtual修饰的函数才能实现多态(在派生类中重写)
抽象类也是类似的用法

virtual int area()
      {
         cout << "Parent class area :" <<endl;
         return 0;
      }

//纯虚函数,表示不存在默认的实现
virtual int area() = 0;

函数使用泛型:template <typename type>

template <typename T>
inline T const& Max (T const& a, T const& b) 
{ 
    return a < b ? b:a; 
} 

类使用泛型:template <class type>

//声明类
template <class T>
class Stack { 
    void push(T const&);  // 入栈
}; 

//实现方法
template <class T>
void Stack<T>::push (T const& elem) 
{ 
    elems.push_back(elem);    
} 

//使用类
Stack<int>         intStack;  // int 类型的栈 
intStack.push(7); 

= delete
表示删除这个方法,常用的方式比如禁止拷贝,禁止运算符重载

  MyClass(const MyClass&) = delete;
  MyClass(MyClass&&) = delete;
  void operator=(const MyClass&) = delete;
  void operator=(MyClass&&) = delete;

二.信号处理

信号是由操作系统传给进程的中断,会提早终止一个程序;
有些信号不能被程序捕获,但是下表所列信号可以在程序中捕获,并可以基于信号采取适当的动作。这些信号是定义在 C++ 头文件 <csignal> 中,在iOS调试中经常能够看到.

SIGABRT 程序的异常终止,如调用 abort。
SIGFPE 错误的算术运算,比如除以零或导致溢出的操作。
SIGILL 检测非法指令。
SIGINT 程序终止(interrupt)信号。
SIGSEGV 非法访问内存。
SIGTERM 发送到程序的终止请求。

C++ 信号处理库提供了 signal 函数,用来捕获突发事件。以下是 signal() 函数的语法:

void (*signal (int sig, void (*func)(int)))(int); 

//可以简化成这样,第一个参数是一个整数,代表了信号的编号;第二个参数是一个函数指针,并且把编号传进去
signal(registered signal, signal handler)

使用案例

void signalHandler( int signum )
{
    cout << "Interrupt signal (" << signum << ") received.\n";
 
    // 清理并关闭
    // 终止程序  
 
   exit(signum);  
 
}
 
int main ()
{
    // 注册信号 SIGINT 和信号处理程序
    signal(SIGINT, signalHandler);  
 
    while(1){
       cout << "Going to sleep...." << endl;
       sleep(1);
    }
 
    return 0;
}

int raise (signal sig)可以用于生成信号,参数是SIGINT、SIGABRT、SIGFPE、SIGILL、SIGSEGV、SIGTERM、SIGHUP其中之一

void signalHandler( int signum )
{
    cout << "Interrupt signal (" << signum << ") received.\n";
 
    // 清理并关闭
    // 终止程序 
 
   exit(signum);  
 
}
 
int main ()
{
    int i = 0;
    // 注册信号 SIGINT 和信号处理程序
    signal(SIGINT, signalHandler);  
 
    while(++i){
       cout << "Going to sleep...." << endl;
       if( i == 3 ){
          raise( SIGINT);
       }
       sleep(1);
    }
 
    return 0;
}

三:C++的多线程

#include <pthread.h>
//pthread_create (thread, attr, start_routine, arg) 

thread 线程指针
attr 用来设置线程属性,可以使用默认值 NULL。
start_routine 线程执行的函数
arg 运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。

线程创建成功时,pthread_create返回0;

//终止线程
pthread_exit (status) 

案例

#include <iostream>
// 必须的头文件
#include <pthread.h>
 
using namespace std;
 
#define NUM_THREADS 5
 
// 线程的运行函数
void* say_hello(void* args)
{
    cout << "Hello Runoob!" << endl;
    return 0;
}
 
int main()
{
    // 定义线程的 id 变量,多个变量使用数组
    pthread_t tids[NUM_THREADS];
    for(int i = 0; i < NUM_THREADS; ++i)
    {
        //参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数
        int ret = pthread_create(&tids[i], NULL, say_hello, NULL);
        if (ret != 0)
        {
           cout << "pthread_create error: error_code=" << ret << endl;
        }
    }
    //等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;
    pthread_exit(NULL);
}

std::thread
C++ 11 之后添加了新的标准线程库 std::thread,std::thread 在 <thread> 头文件中声明,因此使用 std::thread 时需要包含 在 <thread> 头文件

#include<thread>
std::thread thread_object(callable)

其中callable可以是函数指针,函数对象,lambda 表达式都行.

案例

void testfun1() {
    std::cout <<"test threadid is :" << this_thread::get_id() << std::endl;
}

void testfun2(int num) {
    std::cout <<"test threadid is :" << this_thread::get_id() << std::endl;
}

void testfun3(int& num) {
    std::cout <<"test threadid is :" << this_thread::get_id() << std::endl;
}

//使用
std::thread th(testfun1);   //创建线程
int testnum = 1;
std::thread th2(testfun2, testnum); //带参数,参数值传递
std::thread th3(testfun3, std::ref(testnum)); //带参数,参数引用传递

相关文章

  • OC++

    一.回忆一下C++ using可以代替typedef const int& fun(int& a); //修饰返回...

  • Cycript

    Cycript oc++,js,java的混合物. 可以用来探索mac/ios app. 官网地址文档地址 iPh...

  • oc与c++混编,抛弃.mm文件

    写这片文章的起因是,有些朋友不想使用oc++的全部.mm文件的写法,固才有这种混编的转化的方法前期准备: 首先建立...

网友评论

      本文标题:OC++

      本文链接:https://www.haomeiwen.com/subject/smwjgrtx.html