首页 > 编程语言 >候捷C++深入学习

候捷C++深入学习

时间:2024-04-11 14:45:55浏览次数:33  
标签:const String C++ char 深入 str include data 候捷

C++进阶学习

头文件的防卫式声明

#ifndef MYCLASS
#define MYCLASS

Header file content

#endif

成员函数的保护

  • 如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加 const 修饰。例如不要将函数 void Func1(int x) 写成 void Func1(const int x)
  • 如果参数作为输出参数,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加 const 修饰,否则该参数将失去输出功能(因为有 const 修饰之后,不能改变他的值)。
  • 果参数作为输入参数,可以防止数据被改变,起到保护作用,增加程序的健壮性,建议是能加const尽量加上
int getToValue() const //此处需要加入const,防止shu'j
  {
    return m_nTo; //this->m_nTo
  }

返回值优化

return by reference 的情况包括一个value加到另一个value的情况,不适用于两个value相互作用产生新的value的情况,正如黄色内的内容

image-20230223193143584

return by reference 不需要知道接收者是以reference形式接收的

image-20230223193445064

特殊的重载操作符

<< 不能写为成员函数,只能写全局函数,因为cout不能识别复数类型

inline complex
conj (const complex& x){
    return complex(real(x) , -imag(x));
}

#include <iostream>
ostream& //防止第二种情况的发生,需要“cout<<c1”的类型为cout才能接收第二个conj
operator << (ostream& os , const complex& x){ //ostream没有const因为
                                         //向cout内传入数据就是在改变cout
    return os << '(' <<real(x)<<','<<imag(x)<<')';
}
int main()
{
    complex c1(2 , 1);
    cout<<conj(c1);
    cout<<c1<<conj(c1); //②
}

Inline函数

Inline函数的使用

如果是在类中,函数的如果在类定义的时候进行定义,那么,加不加关键字 inline 并没有什么异样,因为,这样的函数都会被默认为是内联函数。

详细:C++经验(十一)-- (inlining)内联函数的使用_slowlytalk的博客-CSDN博客

三种特殊的函数

//构造函数
inline
String::String(const char* cstr = 0){//参数为常量指针
    if(cstr){
        m_data = new char[strlen(cstr) + 1];//"+1"的原因是字符串最后还有一个                                               结束位
        strcpy(m_data , cstr);  
   }
    else{
        m_data = new char[1];
        *m_data = '\0';
    }
}

//析构函数
inline
String::String(){
    delete[] m_data;
}

//拷贝构造函数
inline
String::String(const String& str){
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data , str.m_data);
}

//拷贝赋值函数
inline
String& String::String operator=(const String& str){
    if(this == &str){
        return *this; //监测自我赋值,
    }
    
    delete[] m_data;
    m_data = new char[strlen(strlen m_data) + 1];
    strcpy(m_data , str.m_data);
    return *this;
}

image-20230227202048944

image-20230227202005994

内存管理

若使用array new 则一定要使用array delete

String *p = new String[3];
...
delete[] p; //因为delete的数组所以要有[],否则无法彻底清除

堆和栈

class Complex {....}
...
{
    Complex c1(1,2);//c1所占用的空间来自于Stack
    Complex* p = new Complex(3);//p是个临时对象,空间是从Heap的分配而来的
}    

Stack的生命期结束之后清理,也是auto object

static Stack的生命在作用域结束之后仍然存在,在函数结束后才会结束

global object 在类结束后再消失

delete:先调用dtor(析构函数)后释放memory

new:先分配memory 后调用ctor(构造函数)

static

一般常量类型(未被static修饰)、引用类型,在类内部即可实现初始化,在类外实现初始化的必定是static类型(当然一部分的静态成员,也即同时又是const和integral type的,可在类内初始值设定,这一语法特性并非为所有的编译器所支持,所以一种推荐的做法,即是凡是static类型的,我们总在类外进行初始化,哪怕它在类内已进行初始值设定,只要在类外初始化时不修改其值):

int Test::si = 0;
const int Test::sci = 1;
const double Test::scd = 99.0;

函数模板

遇到不能立刻确定的数据和函数类型,可以用function template 来暂时定义。

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

Composition 表示has-a

template <class T>
class queue{
    protected:
    deque<T> c;//引用了别的类的数据
};

class deque{
 protected:
    Itr<T> star;// 同上
    Ttr<T> finish;
    T** map;
    unsigned int map_size;
};

struct Ttr{
    T* cur;
    T* first;
    T* last;
    T** node;
};

组合下的构造和析构:

构造顺序为由内而外,析构为由外而内

Delegation Composition by reference

image-20230313212706042

vector 的一些基础操作

向尾部加入元素时由两种函数,一个是push_back(),另一个是emplace_back()

  1. push_back 可以接收左值也可以接受右值,接收左值时使用拷贝构造,接收右值时使用移动构造
  2. emplace_back 接收右值时调用类的移动构造
  3. emplace_back 接收左值时,实际上的执行效果是先对传入的参数进行拷贝构造,然后使用拷贝构造后的副本,也就是说,emplace_back在接收一个左值的时候其效果和push_back一致!所以在使用emplace_back 时需要确保传入的参数是一个右值引用,如果不是,请使用std::move()进行转换

一些库函数的练习

String

class String
{
    public:
    String(const char* cstr = 0);//构造函数的声明
    String(const String& str);//构造拷贝函数
    String& operator=(const String& str);//拷贝赋值函数
    ~String();
    char* get_c_str() const{return m_data;}//用于cout的函数
    
    private:
    char* m_data;
}

//构造函数
inline //建议作为内联函数,节省空间
String::String(const char* cstr = 0)
{
    if(cstr){
        m_data = new char[strlen(cstr) + 1];
        strcpy(m_data , cstr);
    }else{//未指定初值
        m_data = new char[1];
        *m_data = '\0';
    }
}

//析构函数
inline
String::~String()
{
    delete[] m_data; //使用array new所以要用delete array
}

//拷贝构造函数
inline
String::String(const String& str)
{
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data , str.m_data);
}

//拷贝赋值函数
inline
String& String::operator(const String& str)
{
    if(this == &str){
        return *this;//自我
    }
    
    delete[] m_data;
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data , str.m_data);
    return *this;
}

STL

体验STL库中模板的组成,一个模板可能是由好几个模板相互叠加而形成的

#include <vector>
#include <algorithm>
#inlcude <functional>
#inlcude <iostream>

using namespace std;

int main(){
    int ia[6] = {27 , 210 , 12 , 47 , 109 , 83};
    vector<int , allocator<int>> vi(ia , ia + 6);//第二个参数可以不写,因为默认分配
    
    cout<<count_if(vi.begin() , vi.end() , not1(bind2nd(less<int>() , 40)));
    
    
    return 0;
}

STL容器

#include <vector>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
#include <algorithm>  //sort()
namespace jj02
{
void test_vector(long& value)
{
    cout << "\ntest_vector().......... \n";
      
vector<string> c;     
char buf[10];
             
clock_t timeStart = clock();                                
    for(long i=0; i< value; ++i)
    {
        try {
            snprintf(buf, 10, "%d", rand());
            c.push_back(string(buf));           
        }
        catch(exception& p) {
            cout << "i=" << i << " " << p.what() << endl; 
                 //曾經最高 i=58389486 then std::bad_alloc
            abort();//捕捉到错误后及时退出程序
        }
    }
    cout << "milli-seconds : " << (clock()-timeStart) << endl;    
    cout << "vector.max_size()= " << c.max_size() << endl;    //1073747823
    cout << "vector.size()= " << c.size() << endl;        
    cout << "vector.front()= " << c.front() << endl;  
    cout << "vector.back()= " << c.back() << endl;    
    cout << "vector.data()= " << c.data() << endl;
    cout << "vector.capacity()= " << c.capacity() << endl << endl;      
 
                                                                                 
string target = get_a_target_string();
    {
    timeStart = clock();//记录第一次时间戳
auto pItem = find(c.begin(), c.end(), target);//返回类型为iterator
    cout << "std::find(), milli-seconds : " << (clock()-timeStart) << endl;  
      //记录事件差
    if (pItem != c.end())
        cout << "found, " << *pItem << endl << endl;
    else
        cout << "not found! " << endl << endl;
    }
 
    {
    timeStart = clock();
    sort(c.begin(), c.end());
    cout << "sort(), milli-seconds : " << (clock()-timeStart) << endl; 
     
    timeStart = clock();        
string* pItem = (string*)::bsearch(&target, (c.data()), 
                                   c.size(), sizeof(string), compareStrings); 
    cout << "bsearch(), milli-seconds : " << (clock()-timeStart) << endl; 
        
    if (pItem != NULL)
        cout << "found, " << *pItem << endl << endl;
    else
        cout << "not found! " << endl << endl;    
    }
     
    c.clear();
    test_moveable(vector<MyString>(),vector<MyStrNoMove>(), value); 
}   
}
#include <list>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio>  //snprintf()
#include <algorithm> //find()
#include <iostream>
#include <ctime> 
namespace jj03
{
void test_list(long& value)
{
    cout << "\ntest_list().......... \n";
      
list<string> c;   
char buf[10];
             
clock_t timeStart = clock();                            
    for(long i=0; i< value; ++i)
    {
        try {
            snprintf(buf, 10, "%d", rand());
            c.push_back(string(buf));       
        }
        catch(exception& p) {
            cout << "i=" << i << " " << p.what() << endl; 
            abort();
        }
    }
    cout << "milli-seconds : " << (clock()-timeStart) << endl;        
    cout << "list.size()= " << c.size() << endl;
    cout << "list.max_size()= " << c.max_size() << endl;    //357913941
    cout << "list.front()= " << c.front() << endl;    
    cout << "list.back()= " << c.back() << endl;      
         
string target = get_a_target_string();      
    timeStart = clock();        
auto pItem = find(c.begin(), c.end(), target);                      
    cout << "std::find(), milli-seconds : " << (clock()-timeStart) << endl;       
     
    if (pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found! " << endl;  
         
    timeStart = clock();        
    c.sort();                       
    cout << "c.sort(), milli-seconds : " << (clock()-timeStart) << endl;              
         
    c.clear();
    test_moveable(list<MyString>(),list<MyStrNoMove>(), value);                             
}   
}

标签:const,String,C++,char,深入,str,include,data,候捷
From: https://www.cnblogs.com/zdyCode/p/18129149

相关文章

  • 生命中的开关:深入探讨Deactivated和Activated生命周期
    在软件开发中,生命周期管理是一个至关重要的概念,特别是在移动应用开发中。在移动应用的开发过程中,Deactivated和Activated生命周期扮演着至关重要的角色。本文将深入探讨Deactivated和Activated生命周期,探讨它们的含义、作用以及如何在应用程序中正确地管理它们。什么是Deactiv......
  • 木棒(c++实现)
    题目乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整......
  • 【C++】gcd函数的写法
    ......
  • 【华为OD】2024年华为OD机试C卷真题集:最新的真题集题库 C/C++/Java/python/JavaScript
    【华为OD】2024年C卷真题集:最新的真题集题库C/C++/Java/python/JavaScript【华为OD】2024年C卷真题集:最新的真题集题库C/C++/Java/python/JavaScript-CSDN博客华为OD机试2024年C卷真题题集题库,有2种分数的题目列表,分别是100分的列表、200分的列表需要订阅请看链接:C卷100......
  • 【C++】深入理解 C++ 中的 auto 关键字
    深入理解C++中的auto关键字1.概念2.用法2.1基本用法2.2结合复杂类型2.3函数返回类型推导2.4使用auto处理复杂类型3.注意事项4.适用场景在C++11标准中引入了auto关键字,它是一项强大的特性,可以大大简化代码的书写,同时提高代码的可读性和灵活性。......
  • 【C++】C++入门
    C++入门什么是缺省参数?缺省参数的语法示例:使用缺省参数注意事项什么是函数重载?函数重载的语法示例:使用函数重载注意事项什么是引用?引用的语法引用的特点示例:使用引用注意事项什么是内联函数?内联函数的优势内联函数的语法示例:使用内联函数注意事项什么是缺省参数......
  • 深入浅出 妙用Javascript中apply、call、bind
    这篇文章实在是很难下笔,因为网上相关文章不胜枚举。巧合的是前些天看到阮老师的一篇文章的一句话:“对我来说,博客首先是一种知识管理工具,其次才是传播工具。我的技术文章,主要用来整理我还不懂的知识。我只写那些我还没有完全掌握的东西,那些我精通的东西,往往没有动力写。炫耀从来......
  • 在远程windows上调试Cmake项目 C++
    记录一下CMake项目MSVC编译器远程调试方法参考资料  教程:在远程Windows计算机上调试CMake项目|MicrosoftLearn1.使用VS打开cmake项目2.右键main.cpp文件,添加调试配置选择C++ 3.会打开一个launch.vs.json文件 配置一下 注意:远程机器那里写需要运行的机器号 ......
  • JAVA学习-深入研究容器.选择接口的不同实现
        Java集合框架提供了多个接口,每个接口都有不同的实现类,以满足不同的需求。以下是几个常用接口及其不同的实现类的概述:1.List接口:  -特点:有序集合,允许重复元素。  -实现类:ArrayList、LinkedList、Vector。  -使用方法:使用add()方法添加元素,使用g......
  • C++ 虚函数与纯虚函数
    C++中的虚函数(virtual)是可以被子类重写的成员函数而纯虚函数(purevirtual)是必须被抽象/基类中的定义的虚函数,必须被派生类实现virtualtypefunction(){}//虚函数virtualvoidfuntion1()=0//纯虚函数主要区别:实现虚函数有实现,而纯虚函数没有实现子类中虚函数可......