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

相关文章

Tomcat版本与Java版本的关系及说明

《Tomcat版本与Java版本的关系及说明》:本文主要介绍Tomcat版本与Java版本的关系及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Tomcat版本与Java版本的关系Tomcat历史版本对应的Java版本Tomcat支持哪些版本的pythonJ

C++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++字符串提取和分割的多种方法

《C++字符串提取和分割的多种方法》在C++编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时,本文将详细探讨如何使用C++标准库中的工具来提取和分割字符串,并分析不同方法的适用... 目录1. 字符串提取的基本方法1.1 使用 std::istringstream 和 >> 操作符示

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

利用Python和C++解析gltf文件的示例详解

《利用Python和C++解析gltf文件的示例详解》gltf,全称是GLTransmissionFormat,是一种开放的3D文件格式,Python和C++是两个非常强大的工具,下面我们就来看看如何... 目录什么是gltf文件选择语言的原因安装必要的库解析gltf文件的步骤1. 读取gltf文件2. 提