笨蛋学C++ 之 C++ 知识点

2024-05-09 19:36
文章标签 c++ 知识点 笨蛋

本文主要是介绍笨蛋学C++ 之 C++ 知识点,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C++ 知识点

    • 指针常量、常量指针、常量指针常量
      • 1.需要了解
        • 什么是指针的指向,什么是指针指向的值
      • 2.指针常量
        • 2.1理解
        • 2.2怎么去看该指针的指向和指针指向的值呢?
        • 2.3总结
      • 3.常量指针
        • 3.1理解
        • 3.2怎么去看该指针的指向和指针指向的值呢?
        • 3.3总结
      • 4.常量指针常量
        • 4.1理解
        • 4.2怎么去看该指针的指向和指针指向的值呢?
        • 4.3总结
      • 5.常函数
        • 在成员函数后加 const 后称为函数为常函数
        • 常函数内不可以修改成员属性
        • 成员属性声明时加关键字mutable后,在常函数中依然可以修改
      • 6.常对象
        • 声明对象前加 const 称为常对象
        • 常对象只能调用常函数
    • 引用
      • 1.引用必须初始化
      • 2.引用在初始化后,不能改变,但是可以进行赋值
      • 3.引用传递,形参修饰实参
      • 4.引用传递不要返回局部变量
      • 5.若函数做左值,则必须返回引用,使用static
      • 6.常量引用(const),无法进行修改,只能读取
    • 函数
      • 1.默认参数
      • 2.占位参数
    • 重载运算符
      • 函数重载(参数类型、参数顺序、参数个数、参数被const修饰)
    • 访问修饰符
    • 拷贝构造函数
      • 1.根据创建完毕的对象来初始化新对象
      • 2.值传递的方式给函数参数传值
      • 3.值方式返回局部对象
    • 浅拷贝和深拷贝
    • this指针
    • 友元(friend)
      • 全局函数做友元
      • 类做友元
      • 成员函数做友元
    • 运算符重载
      • 重载输出运算符
      • 重载递增/递减运算符
      • 重载赋值运算符
      • 重载关系运算符
      • 重载函数调用运算符(仿函数)
    • 模板
      • 1.可以直接用`template <class type>`
      • 2.类模板不能自动推导类型
      • 3.类模板可以指定默认参数
      • 4.类模板的成员函数在调用时创建
      • 5.类模板对象作函数参数
      • 6.类模板对象参数模板化
      • 7.类模板对象类模板化
      • 8.类模板与继承
      • 9.构造函数类外实现
      • 10.分文件编写类模板
      • 11类模板的友元函数

指针常量、常量指针、常量指针常量

1.需要了解

什么是指针的指向,什么是指针指向的值
  • 指针的指向,就是指针变量中存储的内存地址,比如 int *p;,其中*p就是指向int整型的指针
  • 指针指向的值,就是指针指向内存地址所代表的数据,比如 p=&num,其中&num就是内存地址中所存储的数据

2.指针常量

2.1理解

是指用一个 const 修饰一个int 类型常量的指针,所以 *p 的值不能修改,比如const int *p;

2.2怎么去看该指针的指向和指针指向的值呢?
  • 因为 const 修饰的是一个指针,所以该指针的指向不能改变,比如 *p = 20;,这里20就是该指针的指向,指向20的地址
  • 但是被该指针指向的值可以被修改,比如 p=&num;,这里p就可以获取到&num的值
2.3总结
  • 指针本身的地址不可更改,但是指针指向的值可以被修改

3.常量指针

3.1理解

是指用一个 const 修饰一个int *类型的变量,所以 p 的值不能修改,比如 int *const p;

3.2怎么去看该指针的指向和指针指向的值呢?
  • 因为是修饰的是一个变量,所以该指针的指向可以被改变,比如 *p = 20
  • 但是该指针指向的值不能改变,比如 p = &num,这里p在指向一个地址后,就不能指向另一个地址了
3.3总结
  • 指针本身的地址可以修改,但是指针指向的值可以被修改

4.常量指针常量

4.1理解

是指用两个const,一个const修饰变量,一个const修饰int 类型的指针,比如 const int* const p;

4.2怎么去看该指针的指向和指针指向的值呢?
  • 因为是修饰了一个变量,也修饰了一个int类型的指针,所以该指针的指向不能被改变,比如 *p = 20
  • 该指针指向的值也不能被改变,比如 p = &num,这里p在指向一个地址后,就不能指向另一个地址了
4.3总结
  • 指针本身的地址不能修改,但是指针指向的值也不能修改

5.常函数

  • 在成员函数后加 const 后称为函数为常函数
    void showPerson() const{this->name = "lisi";
    }
    
  • 常函数内不可以修改成员属性
    void showPerson() const{//这里会报错this->name = "lisi";
    }
    
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改
    void showPerson() const{//现在就不会报错了this->name = "lisi";
    }mutable string name;
    

6.常对象

  • 声明对象前加 const 称为常对象
    const Person p;//常对象
    
  • 常对象只能调用常函数
    void showPerson() const{cout << "常函数" << endl;
    }
    void infoPerson(){cout << "非常函数" << endl;
    }
    p.showPerson(); //可以调用
    p.infoPerson();//不可以调用
    

引用

1.引用必须初始化

2.引用在初始化后,不能改变,但是可以进行赋值

int a = 20;
int &b = a; //引用进行初始化
int c = 30;
&b = c; //不能改变引用后的值
b = c; //但是可以进行赋值

3.引用传递,形参修饰实参

//函数参数为&a、&b
void swap(int &a,int &b){int temp = a;a = b;b = temp;
}int x = 10;
int y = 20;
swap(x, y);

4.引用传递不要返回局部变量

int &test(){int a = 10;return a;
}int &ref = test();
int &test(){static int a = 10;return a;
}int &ref  = test();

5.若函数做左值,则必须返回引用,使用static

int &test(){static int a = 10;return a;
}test() = 200; //相当于返回的a 是200,不是10

6.常量引用(const),无法进行修改,只能读取

函数

1.默认参数

  • 函数的形参列表中的形参是可以有默认值的
  • 默认参数必须放在参数的末尾
  • 若有传递参数的值,则参数会代替默认参数
  • 若函数声明有默认参数,则函数实现就不能有默认参数

2.占位参数

  • 返回值类型 函数名 (数据类型){}
  • 比如重载运算符时,可以使用到占位运算符

重载运算符

函数重载(参数类型、参数顺序、参数个数、参数被const修饰)

访问修饰符

  • 公共权限,public,类内可以访问,类外可以访问
  • 保护权限,protected,类内可以访问,类外不可以访问,子类可以访问父类中的保护内容
  • 私有权限,private,类内可以访问,类外不可以访问,子类不可以访问父类中的私有内容

拷贝构造函数

1.根据创建完毕的对象来初始化新对象

class Person{
public:string name;Person (string name){this->name = name;}Person (const Person &obj){name = obj.name;}
}Person p1("zhangsan");
Person p2(p1);

2.值传递的方式给函数参数传值

void doWork(Person p){}void test(){Person p;doWork(p);
}

3.值方式返回局部对象

void doWork(){Person p1;return p1;
}void test(){Person p = doWorkd();
}

浅拷贝和深拷贝

Person(const Person &obj){//浅拷贝实现name = obj.name;//深拷贝实现name = 	new string(*obj.name);
}

this指针

  • 当形参和成员变量同名时,可用this指针来区分

    Person(string name){this->name = name;
    }
    
  • 在类的非静态成员函数中返回对象本身,可以使用return *this

    Person& updateName(Person &p){this->name = p.name+"1";return *this;
    }Person p1("zhangsan");
    Person p2("lisi");
    p2.updateName(p1).updateName(p1).updateName(p1);
    

友元(friend)

全局函数做友元

#include <iostream>using namespace std;class Person {friend void showPerson(Person* person);public:string name;Person(string name, int age) {this->name = name;this->age = age;}
private:int age;
};void showPerson(Person* person) {cout << "name = " << person->name << "age = " << person->age << endl;
}
int main(void) {Person p("张三", 22);//直接调用友元函数showPerson(&p);return 0;
}

类做友元

class Father {};
class Person {friend void showPerson(Person* person);//可以访问Person类中的成员friend class Father;
public:string name;Person(string name, int age) {this->name = name;this->age = age;}
private:int age;
};

成员函数做友元

#include <iostream>
using namespace std;//预先声明
class Person;class Father {
public://构造函数Father();Person* person;// 访问Person中的私有成员void showPersonInfo();};
class Person {// 声明友元函数,可以访问私有成员friend void Father::showPersonInfo();public:string name;Person(string name, int age) : name(name), age(age) {} // 使用初始化列表
private:int age;
};//初始化函数
Father::Father() {person = new Person("zhangsan", 22);
}void Father::showPersonInfo() {if (person != nullptr) {cout << "name = " << person->name << ", age = " << person->age << endl;}else {cout << "Person pointer is null!" << endl;}
}int main(void) {// 直接调用友元函数Father father;father.showPersonInfo();return 0;
}

运算符重载

  • 成员函数重载

    类名 operator 运算符(const 类名& 参数名){}
    
  • 全局函数重载

    类名 operator 运算符(const 类名& 参数名1,const 类名& 参数名2){}
    
可重载运算符运算符类型
双目算术运算符+ (加),-(减),*(乘),/(除),% (取模)
关系运算符==(等于),!= (不等于),< (小于),> (大于),<=(小于等于),>=(大于等于)
逻辑运算符||(逻辑或),&&(逻辑与),!(逻辑非)
单目运算符+ (正),-(负),*(指针),&(取地址)
自增自减运算符++(自增),–(自减)
位运算符| (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移)
赋值运算符=, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=
空间申请与释放new, delete, new[ ] , delete[]
其他运算符()(函数调用),->(成员访问),,(逗号),[](下标)
不可重载运算符运算符类型
成员访问运算符.
成员指针访问运算符.* ,->*
域运算符::
长度运算符sizeof
条件运算符?:
预处理符号#

重载输出运算符

ostream& operator<<(ostream &cout, Person &p){cout << "name = " << p.name;return cout;
}Person p;
p.name = "zhangsan";
cout << p << "hello" << endl;

重载递增/递减运算符

#include <iostream>
using namespace std;class MyInteger {
public:MyInteger() {this->num = 0;}int num;//重载前置++运算符MyInteger& operator++() {//先进行运算this->num ++;//再将自身返回return *this;}//重载后置++运算符MyInteger operator++(int) {//先记录MyInteger temp = *this;//后递增this->num++;//再返回记录结果return temp;}
};
ostream& operator<<(ostream &cout, MyInteger myInt) {cout << myInt.num;return cout;
}
int main(void) {MyInteger myInt;cout << ++(++myInt) << endl;MyInteger myInts;cout << (myInts++) << endl;cout << (myInts) << endl;return 0;
}

重载赋值运算符

#include <iostream>using namespace std;class Person {
public:Person(int age) {this->age = new int(age);}int *age;Person& operator=(Person &p) {//编译器默认是浅拷贝,即this->age = age;//采用深拷贝if (this->age != NULL) {delete this->age;age = NULL;}this->age = new int(*p.age);return *this;}
};
int main(void) {Person p1(10);Person p2(20);Person p3(30);p3 = p2 = p1;cout << "p1的年龄为:" << *p1.age << endl;cout << "p2的年龄为:" << *p2.age << endl;cout << "p3的年龄为:" << *p3.age << endl;return 0;
}

重载关系运算符

#include <iostream>using namespace std;
class Person {
public:Person( string name,int age) {this->age = age;this->name = name;}int age;string name;bool operator== (Person &p) {if (this->name == p.name && this->age == p.age) {return true;}return false;}};int main(void) {Person p1("zs", 12);Person p2("ls", 12);if (p1 == p2) {cout << "p1 == p2 " << endl;}else {cout << "p1 != p2 " << endl;}return 0;
}

重载函数调用运算符(仿函数)

#include <iostream>using namespace std;class MyPrint {
public://重载函数调用运算符void operator()(string test) {cout << test << endl;}};
int main(void) {MyPrint myPrint;myPrint("111测试111");return 0;
}

模板

1.可以直接用template <class type>

2.类模板不能自动推导类型

3.类模板可以指定默认参数

4.类模板的成员函数在调用时创建

class Person1
{
public:void showPerson1(){cout << "Person1 show" << endl;}
};class Person2
{
public:void showPerson2(){cout << "Person2 show" << endl;}
};template<class T>
class MyClass
{
public:T obj;//类模板中的成员函数,并不是一开始就创建的,而是在模板调用时再生成void fun1() { obj.showPerson1(); }void fun2() { obj.showPerson2(); }};void test01()
{MyClass<Person1> m;m.fun1();//m.fun2();//编译会出错,说明函数调用才会去创建成员函数
}int main() {test01();system("pause");return 0;
}

5.类模板对象作函数参数

//1、指定传入的类型
void printPerson1(Person<string, int> &p) 
{p.showPerson();
}
void test01()
{Person <string, int >p("孙悟空", 100);printPerson1(p);
}

6.类模板对象参数模板化

//2、参数模板化
template <class T1, class T2>
void printPerson2(Person<T1, T2>&p)
{p.showPerson();cout << "T1的类型为: " << typeid(T1).name() << endl;cout << "T2的类型为: " << typeid(T2).name() << endl;
}
void test02()
{Person <string, int >p("猪八戒", 90);printPerson2(p);
}

7.类模板对象类模板化

//3、整个类模板化
template<class T>
void printPerson3(T & p)
{cout << "T的类型为: " << typeid(T).name() << endl;p.showPerson();}
void test03()
{Person <string, int >p("唐僧", 30);printPerson3(p);
}

8.类模板与继承

template<class T>
class Base
{T m;
};//class Son:public Base  //错误,c++编译需要给子类分配内存,必须知道父类中T的类型才可以向下继承
class Son :public Base<int> //必须指定一个类型
{
};
void test01()
{Son c;
}//类模板继承类模板 ,可以用T2指定父类中的T类型
template<class T1, class T2>
class Son2 :public Base<T2>
{
public:Son2(){cout << typeid(T1).name() << endl;cout << typeid(T2).name() << endl;}
};void test02()
{Son2<int, char> child1;
}int main() {test01();test02();system("pause");return 0;
}

9.构造函数类外实现

#include <string>//类模板中成员函数类外实现
template<class T1, class T2>
class Person {
public://成员函数类内声明Person(T1 name, T2 age);void showPerson();public:T1 m_Name;T2 m_Age;
};//构造函数 类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {this->m_Name = name;this->m_Age = age;
}//成员函数 类外实现
template<class T1, class T2>
void Person<T1, T2>::showPerson() {cout << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl;
}void test01()
{Person<string, int> p("Tom", 20);p.showPerson();
}int main() {test01();system("pause");return 0;
}

10.分文件编写类模板

  • 将声明和实现写到同一个文件中,并更改后缀名为.hpp

    #pragma once
    #include <iostream>
    using namespace std;
    #include <string>template<class T1, class T2>
    class Person {
    public:Person(T1 name, T2 age);void showPerson();
    public:T1 m_Name;T2 m_Age;
    };//构造函数 类外实现
    template<class T1, class T2>
    Person<T1, T2>::Person(T1 name, T2 age) {this->m_Name = name;this->m_Age = age;
    }//成员函数 类外实现
    template<class T1, class T2>
    void Person<T1, T2>::showPerson() {cout << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl;
    }//将声明和实现写到一起,文件后缀名改为.hpp
    #include "person.hpp"
    void test()
    {Person<string, int> p("Tom", 10);p.showPerson();
    }

    11类模板的友元函数

    #include <string>//2、全局函数配合友元  类外实现 - 先做函数模板声明,下方在做函数模板定义,在做友元
    template<class T1, class T2> class Person;//如果声明了函数模板,可以将实现写到后面,否则需要将实现体写到类的前面让编译器提前看到
    //template<class T1, class T2> void printPerson2(Person<T1, T2> & p); template<class T1, class T2>
    void printPerson2(Person<T1, T2> & p)
    {cout << "类外实现 ---- 姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
    }template<class T1, class T2>
    class Person
    {//1、全局函数配合友元   类内实现friend void printPerson(Person<T1, T2> & p){cout << "姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;}//全局函数配合友元  类外实现friend void printPerson2<>(Person<T1, T2> & p);public:Person(T1 name, T2 age){this->m_Name = name;this->m_Age = age;}private:T1 m_Name;T2 m_Age;};//1、全局函数在类内实现
    void test01()
    {Person <string, int >p("Tom", 20);printPerson(p);
    }//2、全局函数在类外实现
    void test02()
    {Person <string, int >p("Jerry", 30);printPerson2(p);
    }int main() {//test01();test02();system("pause");return 0;
    }
    

这篇关于笨蛋学C++ 之 C++ 知识点的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/974300

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

基本知识点

1、c++的输入加上ios::sync_with_stdio(false);  等价于 c的输入,读取速度会加快(但是在字符串的题里面和容易出现问题) 2、lower_bound()和upper_bound() iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。 iterator upper_bou

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给