c++中的特殊成员(const,stacic,友元,类间关系)

2023-10-11 17:59

本文主要是介绍c++中的特殊成员(const,stacic,友元,类间关系),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 1.初始化参数列表(特殊的构造函数的写法)
  • 2. const成员
    • 2.1 const 数据成员
    • 2.2 const 成员函数
    • 2.3 const 对象
  • 3.静态数据成员
    • 3.1 static数据成员
      • 1.定义及初始化
      • 2. 注意调用
      • 3. 静态数据成员会保留上一次执行的结果
    • 3.2 static成员函数
      • 1. static 修饰的函数
      • 2.static函数的调用
  • 4. 友元关系
    • 1. 友元函数
    • 2.友元类
  • 5. 类的组合
  • 6. 类中成员函数指针

1.初始化参数列表(特殊的构造函数的写法)

与其他函数不同,构造函数除了有名字,参数列表和函数体之外,
还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段。

初始化参数列表 :构造函数名(参数1,参数2,…):成员1(参数1),成员2(参数2)…{}
初始化参数列表很重要

#include <string>
class MM 
{
public://1.普通的构造函数写法,很少用MM(string name){this->name = name;}//2.初始化参数列表 --->很重要 如集成,类的组合常常使用MM(string name, int age) :name(name), age(age){}//构造函数名(参数1,参数2,...):成员1(参数1),成员2(参数2)....{}	
protected:string name;int age;
};

初始化参数列表不能用this指针

//MM(string name, int age) :this->name(name), this->age(age){}//错误

2. const成员

const: 不能修改

2.1 const 数据成员

  1. 常数成员在构造函数时必须采用初始化参数列表的方式进行初始化
  2. num是常数据成员,必须采用初始化参数列表
  3. name,age是普通数据成员,可以用this指针,也可以用初始化列表
#include <string>
class MM 
{
public:MM(string name, int age, int num) :num(num) //常数据成员{this->name = name;  //普通数据成员this->age = age;}
protected:string name;    //普通数据成员int age;const int num;	//假如这是身份证号:必须使用初始化参数列表
};
普通数据成员,也可以用初始化列表
#include <string>
class MM 
{
public:MM(string name, int age, int num) :name(name),age(age),num(0) {}//num可以初始化为一常数,这里举例为0
protected:string name;    //普通数据成员,可随意int age;const int num;	//常数据成员,必须使用初始化参数列表
};
  1. 构造函数必须要初始化常数据成员
#include <string>
class MM 
{
public:MM(string name):num(0) //初始化列表的方式{this->name = name;}
protected:string name;int age;const int num;			//必须使用初始化参数列表
};
  1. char*类型的初始化列表
#include<string>
class boy
{
public:boy(const char* str) :str(str) {}boy() :str("ILoveyou") {}const char* str;
};

2.2 const 成员函数

  1. 注意写法:const放在函数后面,只能写在类里面
  2. 注意限定:常成员函数不能修改数据成员
  3. 常成员函数可以和普通函数共存
#include <string>
class MM 
{
public:MM(string name, int age, int num) :num(num) //构造函数完成初始化{this->name = name;this->age = age;} void print() //普通函数{cout << "普通函数" << endl;cout << name << ":" << age << endl;}void print() const	//常成员函数{cout << "常函数" << endl;//可以使用数据成员,但是不能修改cout << name << ":" << age<<":"<<num << endl;}
protected:string name;int age;const int num;			//必须使用初始化参数列表
};

2.3 const 对象

常对象只能调用常成员函数,普通对象优先调用普通函数

int main() 
{ const MM  mm("Love");   //常对象mm.print();				//常对象只能调用常成员函数MM myMM("小仙女", 18);	//普通对象优先调用普通函数myMM.print();return 0;
}

3.静态数据成员

static修饰的变量成为静态变量,

3.1 static数据成员

1.定义及初始化

  1. 定义static变量时,需要前缀static,并且依旧受权限限定词(public, protected)限定
  2. static数据成员必须初始化,用类名前缀,不再需要static修饰
  3. static数据成员必须初始化,类似全局初始化,需要在类外进行初始化,也不能在主函数中初始化
class MM 
{
public://初始化参数列表的方式比较多MM(string name) :name(name) {count++;}
protected:string name;
public:static int count; //需要前缀static,依旧受权限限定词限定};
//类外必须初始化,要用类名限定,不再需要static
int MM::count = 0;   //用类名前缀

2. 注意调用

  1. 他的使用可以不需要对象 静态数据成员属于类,不属于对象
  2. 依旧受权限和类名限定词限定
  3. 类似于一个写在类里面的全局变量
class MM 
{
public:MM(string name) :name(name) {}
protected:string name;
public:static int count;
};
int MM::count = 0;
int main() {
//静态数据成员依旧受权限限定词限定,count为受保护类型限定时,主函数会报错cout << MM::count << endl;return 0;
}

3. 静态数据成员会保留上一次执行的结果

class MM 
{
public:MM(string name) :name(name) {count++;}
protected:string name;
public:static int count;
};
int MM::count = 0;
int main() {cout << MM::count ;MM mm1("yykk");MM mm2("oracle");MM mm3("LBW");cout << MM::count ;return 0;
}

运行结果是03
总共调用了三次初始化列表
普通函数使用静态数据成员是可以随便使用的

3.2 static成员函数

static成员函数: static修饰的类内函数
通常用来写一些特定的接口,一些重写的函数

1. static 修饰的函数

类中实现
类中实现 statick+普通函数

class MM 
{
public:static int count;  //静态成员变量static void printInfo()  //类中实现{.........}	static void printData(MM object){......}
};

类外实现

  1. 类外实现的语法:
    类外实现不需要static修饰,但是需要有类名限定
class MM 
{
public:static int count;       //静态成员变量static void printInfo();    //类外实现的声明static void printData(MM object); 
protected:string name;
};
//类外实现不需要static修饰,需要类名限定
void MM::printInfo() 
{......}
void MM::printData(MM object) 
{.........}
  1. 调用与访问问题
    1. 调用: 不需要对象
    2. 静态函数访问静态数据成员,没有任何问题
    3. 静态成员函数访问非静态数据成员,通过指定对象,传参传一个对象进去指定
    4. 传参的静态成员函数也可以访问受保护的,私有的成员变量
class MM 
{
public:static int count;           //静态成员变量static void printInfo();    static void printData(MM object);  //指定对象的函数声明
protected:string name;
};
void MM::printInfo()          //未传参
{//静态函数访问静态数据成员,没有任何问题cout << count << endl;
}
void MM::printData(MM object)  //传参
{//静态成员函数访问非静态数据成员,通过指定对象,否则无法访问cout << object.name << endl; //指定对象,可以访问具有保护属性,私有属性的成员变量cout << count << endl;        //不需要指定对象
}

2.static函数的调用

静态函数的调用
可以通过 类名:: 进行调用,也可以通过 对象. 进行调用

#include <string>
class MM 
{
public:MM(string name) :name(name) {} //初始化列表static void printInfo();           //未传参的静态成员函数static void printData(MM object);  //传参的静态成员函数static int count;                  //静态成员变量
protected:string name;
};
int MM::count = 0;     //静态成员变量的初始化
void MM::printInfo()   //
{cout << count << endl;}
void MM::printData(MM object) 
{cout << object.name << endl;cout << count << endl;}
int main() {MM mm1("yykk");    //定义两个对象MM mm2("oracle"); MM mm3("ojbk"); //静态函数的调用MM::printInfo();    //通过类进行调用MM::printData(mm3);mm2.printData(mm3); //通过对象进行调用mm1.printData(mm2);return 0;
}

4. 友元关系

1. 友元函数

friend关键字修饰的函数就是友元函数:

  1. 友元函数不属于类,可以在类中实现,也可以在类外实现
  2. 类外实现不需要friend修饰,不需要加类名限定,就当做普通函数写
  3. 类外实现需要在类内函数声明
  4. 友元函数是在当前函数中赋予对象具有打破类的权限限定的作用,即在这个函数中,所使用的对象具有访问当前类的任何属性,保护私有都可以访问,打破类的隐藏和封装性
    1. 传参的对象/对象指针
    2. 在函数体创建对象
  5. 单个类的友元函数可以函数重载
class MM 
{friend void makeBoyFriend(); //类内函数声明friend void makeBoyFriend(MM object); //函数重载
public:MM(string name, int age, int money) :name(name), age(age), money(money) {}string name;
protected:void print() {cout << name << ":" << age << ":" << money << endl;}int age;
private:int money;
};
void makeBoyFriend() //不需要friend,不需要类名限定
{//在当前函数中任何对象都具有打破类的权限限定MM boy("yykk", 18, 100);  //能够访问类内任何属性boy.print();cout << boy.name << ":" << boy.age << boy.money << endl;
}

*以另一个类的成员函数为友元函数

  1. 用类名限定
  2. 要声明一下
  3. 实现顺序问题
#include<iostream>
#include<string>
using namespace std;
class Girl;
class Boy
{
public:void makeGirlFriend(Girl girl);
protected:
};
class  Girl
{   friend void Boy::makeGirlFriend(Girl girl);
public:Girl(string name, int age) :name(name), age(age) {}string name;
protected:int age;
};
void  Boy::makeGirlFriend(Girl girl)
{cout << girl.name << ":" << girl.age << endl;}
int main()
{   Girl girl("Oracle", 19);Boy boy;boy.makeGirlFriend(girl);return 0;
}

在这里插入图片描述

2.友元类

下面代码中Boy类就是Girl类的友元类

class Girl 
{friend class Boy;
public:......
protected:......
};
class Boy 
{
public:.......
protected:.......
};

在Boy类的任何地方girl对象都可以访问girl任何属性

class Girl 
{   friend class Boy;
public:Girl(string name, int age) :name(name), age(age) {}string name;
protected:int age;
};
class Boy 
{public:void print()       //两种打印的方式{   Girl girl("Oracle", 18);//在当前类的任何地方girl对象都可以访问girl任何属性cout << girl.name << ":" << girl.age << endl;}void print(Girl object) {cout << object.name << ":" << object.age << endl;}
protected:
};

*互为友元,A类和B类互为友元类

class A 
{friend class B;
public:
protected:
};
class B 
{friend class A;
public:
protected:
};

5. 类的组合

以另一个类的对象为数据成员:

  1. 构造函数写法
    1. 必须初始化参数列表方式调用组合类的构造函数
    2. 组合类必定会调用其他类的组合
  2. 构造和析构顺序问题
#include <iostream>
using namespace std;
class Clothes 
{
public:Clothes(int color) :color(color) {cout << "A" << endl;}
protected:int color;
};
class Cosmetics 
{
public:Cosmetics(int moeny) :money(money) {cout << "B" << endl;}
protected:int money;
};
class MM 
{
public://MM(string name,int color,int money) :Cosmetic(money), Clo(color){   this->name = name;cout << "C" << endl;}
protected:string name;//构造顺序和这个声明顺序有关Clothes Clo;  Cosmetics Cosmetic;
};
int main() 
{MM mm("LBW",1,2);	//A B Creturn 0;
}

构造顺序

6. 类中成员函数指针

#include <iostream>
using namespace std;
class  MM 
{
public:MM(string  name, int age) :name(name), age(age) {}void print() {cout << name << "\t" << age << endl;}
protected:string name;int age;
};
int main() 
{MM mm("Bug", 10);//error C3867: “MM::print”: 非标准语法;请使用 "&" 来创建指向成员的指针//1. "&" 来创建指向成员的指针		&MM::print//错误写法 void MM::(*p)()//错误写法 void (*MM::p)(); void (MM:: * p)() = &MM::print;(mm.*p)();		//调用的时候写法上注意点return 0;
}

这篇关于c++中的特殊成员(const,stacic,友元,类间关系)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

C++中使用vector存储并遍历数据的基本步骤

《C++中使用vector存储并遍历数据的基本步骤》C++标准模板库(STL)提供了多种容器类型,包括顺序容器、关联容器、无序关联容器和容器适配器,每种容器都有其特定的用途和特性,:本文主要介绍C... 目录(1)容器及简要描述‌php顺序容器‌‌关联容器‌‌无序关联容器‌(基于哈希表):‌容器适配器‌:(

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

Perl 特殊变量详解

《Perl特殊变量详解》Perl语言中包含了许多特殊变量,这些变量在Perl程序的执行过程中扮演着重要的角色,:本文主要介绍Perl特殊变量,需要的朋友可以参考下... perl 特殊变量Perl 语言中包含了许多特殊变量,这些变量在 Perl 程序的执行过程中扮演着重要的角色。特殊变量通常用于存储程序的

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

【C++ Primer Plus习题】13.4

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

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对象