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++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元

Python获取C++中返回的char*字段的两种思路

《Python获取C++中返回的char*字段的两种思路》有时候需要获取C++函数中返回来的不定长的char*字符串,本文小编为大家找到了两种解决问题的思路,感兴趣的小伙伴可以跟随小编一起学习一下... 有时候需要获取C++函数中返回来的不定长的char*字符串,目前我找到两种解决问题的思路,具体实现如下:

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(