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

【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;  // 成员属性:高

    // 默认构造函数,初始化长宽高为1
    Box()
    {
        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对象的长宽高各加1
    void operator ++ ()
    {
        cout << "前++" << endl;
        this->height++;  // 高度加1
        this->width++;   // 宽度加1
        this->length++;  // 长度加1
    }

    // 重载后++运算符,用于将当前Box对象的长宽高各加1,并返回加1前的值
    Box operator ++(int)  // 有占位符的是后++
    {
        cout << "后++" << endl;
        Box other = *this;  // 先保存当前对象的值
        this->height++;  // 高度加1
        this->width++;   // 宽度加1
        this->length++;  // 长度加1
        return 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的和,并赋值给c
    a = b = c;  // 调用重载的赋值运算符,将c的值赋给b,再将b的值赋给a
    a += b;     // 调用重载的累加运算符,将b的值累加到a
    ++a;        // 调用重载的前++运算符,将a的长宽高各加1
    cout << "a.height:" << a.height << " a.width:" << a.width << " a.length:" << a.length << endl;  // 输出a的长宽高

    a++;        // 调用重载的后++运算符,将a的长宽高各加1
    cout << "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.kler.cn/a/469977.html

相关文章:

  • Vue项目中的问题汇总(持续更新中)
  • 微信小程序校园自助点餐系统实战:从设计到实现
  • 批量写入数据到数据库,卡顿怎么解决
  • 「Mac畅玩鸿蒙与硬件53」UI互动应用篇30 - 打卡提醒小应用
  • 微服务-Eureka
  • 密码学原理技术-第十一章-Hash Functions
  • Spring Boot教程之四十七:Spring Boot ——JDBC
  • BMS应用软件开发 — 2 单体电池的基本结构和工作原理
  • linux redis/: Permission denied,当前用户对该目录没有访问权限
  • Jdbc笔记01
  • 探索报表软件的世界:山海鲸、Tableau与Power BI比较
  • 头文件iostream的一些函数使用
  • 半导体数据分析: 玩转WM-811K Wafermap 数据集(二) AI 机器学习
  • ElasticSearch基础-文章目录
  • mapreduce 工作流程
  • 头歌python实验:网络安全应用实践-恶意流量检测
  • 【FTP 协议】FTP主动模式
  • Rabbitmq消息补偿机制
  • 【机器学习】从监督学习的懵懂起步至迁移学习的前沿瞭望
  • iOS - 自定义引用计数(MRC)
  • Cursor 实战技巧:好用的提示词插件Cursor Rules
  • 深度解读 “驭风行动”
  • Latex中inproceedings 和 article的区别
  • 【wiki知识库】08.添加用户登录功能--后端SpringBoot部分
  • mac 使用zip2john破解zip压缩包密码
  • Ruby语言的编程范式