当前位置: 首页 > news >正文

【C++】const关键字_运算符重载_继承

目录

Const关键字

常量

常量指针

参数传递

返回值

成员函数

const作用域

运算符重载

继承

继承同名静态成员函数

构造和析构的调用顺序

多重继承

菱形继承(二义性)

虚继承的工作原理

友元

常(成员)函数


Const关键字

        在C++中,const关键字用于指定变量的值在初始化后不能被修改。它主要用于提高代码的安全性和可读性。

常量
const int a = 100;    //常量,初始化后不可修改
常量指针

• `const`在指针前:指针指向的数据是常量,不能被修改。

• `const`在指针后:指针本身是常量,不能指向其他地址。

#include <iostream>  
using namespace std;
int value1 = 100;
int value2 = 2;int main()
{const int* ptr = &value1; //常量指针,const修饰ptr指向的值,可以不用进行初始化int* const ptr1 = &value2;   //指针常量,ptr1初始化后不可指向其他地址,需要进行初始化const int* const ptr3 = &value1; //ptr3指向的地址和值都不可修改return 0;
}
参数传递

• `const`修饰函数参数,可以防止函数内部修改参数的值,这对于引用和指针参数特别有用。

void print(const int& value) {}   // value不能被修改
返回值

• `const`修饰返回值,可以防止返回值被修改。通常用于返回对象时,防止返回的对象被修改。

const string& getName() const {    //防止返回值name被修改return name;
}
成员函数

在成员函数的末尾加上`const`,该成员函数不会修改对象的状态(即不会修改对象的任何成员变量)

class MyClass {
public:int getValue() const {  // const成员函数return value;}
private:int value;
};
const作用域
//跨多个类文件(.cpp)文件使用的时候,定义和引用的地方都要加extern
//a.cpp
extern const int num =1;//b.cpp
extern const int num;//跨头文件(.h)引用时,可通过书写头文件引用
//a.h
const int value =1;//a.cpp
#include"a.h"
int main(){cont<<value;
}

运算符重载

        运算符重载实质上是函数重载(重载+,-,*等函数),也是一种C++静态多态(编译时多态),静态多态是在编译时由编译器确定不会产生额外的开销。

        

#include <iostream>using namespace std;class Box
{
public:int length;  // 成员属性:长int width;   // 成员属性:宽int height;  // 成员属性:高// 默认构造函数,初始化长宽高为1Box(){length = 1;width = 1;height = 1;}// 带参数的构造函数,用于初始化长宽高Box(int length, int width, int height){this->length = length;  // 使用this指针区分成员变量和参数this->width = width;this->height = height;}// 重载加法运算符,用于两个Box对象相加Box operator + (const Box& other){Box temp;  // 创建一个临时Box对象temp.height = this->height + other.height;  // 高度相加temp.width = this->width + other.width;     // 宽度相加temp.length = this->length + other.length;  // 长度相加return temp;  // 返回临时Box对象}// 重载赋值运算符,用于将一个Box对象的值赋给另一个Box对象Box& operator = (const Box& other){this->height = other.height;  // 赋值高度this->width = other.width;    // 赋值宽度this->length = other.length;  // 赋值长度return *this;  // 返回当前对象的引用,支持链式赋值}// 重载累加运算符,用于将一个Box对象的值累加到当前Box对象void operator +=(const Box& other){this->height += other.height;  // 高度累加this->width += other.width;    // 宽度累加this->length += other.length;  // 长度累加}// 重载前++运算符,用于将当前Box对象的长宽高各加1void operator ++ (){cout << "前++" << endl;this->height++;  // 高度加1this->width++;   // 宽度加1this->length++;  // 长度加1}// 重载后++运算符,用于将当前Box对象的长宽高各加1,并返回加1前的值Box operator ++(int)  // 有占位符的是后++{cout << "后++" << endl;Box other = *this;  // 先保存当前对象的值this->height++;  // 高度加1this->width++;   // 宽度加1this->length++;  // 长度加1return other;  // 返回加1前的值}// 重载小于运算符,用于比较两个Box对象的长度bool operator<(const Box& other){return this->length < other.length;  // 比较长度}// 重载等于运算符,用于比较两个Box对象的长度是否相等bool operator == (const Box& other){return this->length == other.length;  // 比较长度}
};// 重载输出流运算符,用于输出Box对象的信息
ostream& operator<<(ostream& out, Box other)
{out << other.height << " " << other.length << " " << other.width << endl;  // 输出高、长、宽return out;  // 返回输出流对象,支持链式输出
}int main()
{Box a, b;  // 创建两个Box对象a和b,默认初始化Box c;     // 创建一个Box对象c,默认初始化c = a + b;  // 调用重载的加法运算符,计算a和b的和,并赋值给ca = b = c;  // 调用重载的赋值运算符,将c的值赋给b,再将b的值赋给aa += b;     // 调用重载的累加运算符,将b的值累加到a++a;        // 调用重载的前++运算符,将a的长宽高各加1cout << "a.height:" << a.height << " a.width:" << a.width << " a.length:" << a.length << endl;  // 输出a的长宽高a++;        // 调用重载的后++运算符,将a的长宽高各加1cout << "a.height:" << a.height << " a.width:" << a.width << " a.length:" << a.length << endl;  // 输出a的长宽高cout << a << b << c << endl;  // 调用重载的输出流运算符,输出a、b、c的信息return 0;
}

继承

继承同名静态成员函数
class father
{
public:static void fun(){cout << "father's fun" << endl;}
};
class son :public father
{
public:static void fun(){cout << "son's fun" << endl;}
};
int main()
{son::fun();//输出"son's fun"son::father::fun();//输出"father's fun"return 0;
}
构造和析构的调用顺序
  • 构造函数:派生类(子类)的构造函数会首先调用基类的构造函数来初始化基类(父类)部分,然后初始化派生类部分。如果基类有默认构造函数,可以不显式调用。
  • 析构函数:析构函数的调用顺序与构造函数相反,先调用派生类的析构函数,再调用基类的析构函数
#include <iostream>using namespace std;class father
{
public:int temp;father(int a){cout << "父类构造1" << endl;}father(int a, int b){cout << "父类构造2" << endl;}void fun(){cout << "father fun" << endl;}~father(){cout << "父类析构" << endl;}
};
class son :public father
{
public:son() :father(2, 4)//父类没有无参构造,子类声明父类走的哪个构造{cout << "子类构造" << endl;}~son(){cout << "子类析构" << endl;}
};
int main()
{son s;return 0;
}
多重继承

        C++支持多重继承,子类可同时继承多个父类

class B  {};class C  {};class D : public B, public C {};
菱形继承(二义性)

 

        菱形继承会产生二义性问题(D中继承的变量a,不知道是来自类B还是类C),可以通过虚继承利用作用域来解决二义性

虚继承的工作原理
  • 共享基类实例:通过虚继承,类B和类C共享同一个类A的实例,而不是各自拥有一个独立的实例。
  • 构造函数调用:当创建类D的对象时,类A的构造函数只会被调用一次。这是通过在类D的构造函数中显式调用类A的构造函数来实现的。如果类D的构造函数中没有显式调用类A的构造函数,则会调用类A的默认构造函数(如果存在).
  • 访问路径:由于类A的实例是共享的,类D可以通过类B或类C访问类A的成员,但访问路径是唯一的,因为类A的实例只有一个.

友元

        友元可以让一个类访问另一个类私有成员,使用友元函数/类 的优缺点:

优点:提高函数效率,表达清晰简单

缺点:破坏类的封装机制,尽量不使用

class A
{
private:int temp=1;friend void fun();//声明函数fun为类A的友元函数friend class B;//声明类B为类A的友元函数,在类B中可以访问类A的私有成员变量
};
void fun()
{A a;cout <<"a.temp: "<< a.temp << endl;
}
class B
{
public:void Api(){A a;cout << "a.temp: " << a.temp << endl;}
};
int main()
{fun();B b;b.Api();return 0;
}
常(成员)函数
  • 定义:常函数使 调用类的成员函数不会对类做任何修改
  • 格式:返回值 函数名(参数)const {函数体}
  • 特点:
    • 可读不可写数据成员,也就是无法修改
    • 常函数的this指针式const Class *型
    • 常成员函数只能调用常成员函数,不能更改类中的成员状态(与const相似)
    • 常函数能修改传入自身的形参以及内部定义的局部变量
    • 常对象只能调用常函数,不能调用普通函数。
#include <iostream>using namespace std;class Student
{
public:Student() {}Student(const string& nm, int sc = 0) :name(nm), score(sc) {}void set_student(const string& nm, int sc = 0){name = nm;score = sc;}const string& get_name()const;//常函数int get_score() const{return score;}
private:string name;int score;
};
const string& Student::get_name()const
{//set_student();//常函数只能调用常函数,不能调用类中未使用const修饰的成员函数。get_score();return name;
}
void output_student(const Student& student)
{cout << "student.get_score(): " << student.get_score() << endl;
}
int main()
{Student stu("wang",85);output_student(stu);
}


http://www.mrgr.cn/news/82789.html

相关文章:

  • 前端开发 vue 中如何实现 u-form 多个form表单同时校验
  • 创建型模式4.原型模式
  • 【FlutterDart】 listView.builder例子二(14 /100)
  • 递归思想的深度理解——汉诺塔问题和青蛙跳台阶问题
  • React知识盲点——组件通信、性能优化、高级功能详解(大纲)
  • Python爬虫基础——认识网页结构(各种标签的使用)
  • 基于深度学习的视觉检测小项目(七) 开始组态界面
  • 141.《mac m系列芯片安装mongodb详细教程》
  • 高效内存管理与调试技巧:深入解析 AddressSanitizer
  • Elasticsearch:基础概念
  • 对比显式启用-u_printf_float和-u_scanf_float前后的代码内存体量实验
  • 基于Arduino的FPV头部追踪相机系统
  • 网络的分类与体系结构
  • ply和splat点云在线转换工具
  • 大数据组件(三)快速入门实时计算平台Dinky
  • Vmware安装centos
  • 【Windows】Windows系统中怎么查看被隐藏的文件夹?
  • Python教程丨Python环境搭建 (含IDE安装)——保姆级教程!
  • JDK、JRE、JVM三者的关系、JDK8的新特性、JVM内存结构,堆栈的区别
  • MyBatis学习笔记-数据加密解密
  • github gitbook写书
  • vue项目上传ofd文件,导致文件类型丢失问题
  • 【C#】C# 使用onnxruntime报错记录
  • 51单片机——步进电机模块
  • 【AI落地】AI生成测试用例,claude or gpt?(提效至少 50%)
  • Linux: 关于 mount 的一些细节