【C++】类与对象

一、从结构体到类

对于面向对象编程来说,一切都是对象,对象用类来描述。
类把对象的数据和操作数据的方法作为一个整体考虑。

1.语法

定义类的语法:
class 类名
{
public:
成员一的数据类型 成员名一;
成员二的数据类型 成员名二;

成员n的数据类型 成员名n;
};
注意:

  • 类的成员可以是变量,也可以是函数;
  • 类的成员变量也叫属性;
  • 类的成员函数也叫行为/方法,类的成员函数可以定义在类的外面;

例:
void setvalue(string name, int age);//成员函数在类中的声明,setvalue为函数名
void 类名::stevalue(string name, int age) {函数主体} //函数在类外的定义

  • 用类定义一个类的变量叫做创建(或实例化)一个对象;
  • 类的成员变量和成员函数的作用域和生命周期与对象的作用域和生命周期相同。

二、类的访问权限

1.权限种类

类的成员有三种访问权限:public、private和protected,分别表示公有的、私有的和受保护的。
在类的内部(类的成员函数中),无论成员被声明为public还是private,都是可以访问的。
在类的外部(定义类的代码外),只能访问public成员,不能访问private、protected成员。

2.使用说明

在一个类体的定义中,private和public可以使用多次。
结构体的成员缺省为public,类的成员缺省为private。
private的意义在于隐藏类的数据和实现,把需要向外暴露的成员声明为public。

三、类的简单使用说明

编程思想和方法的改变。

  1. 类的成员函数可以直接访问该类的其他成员函数;
  2. 类的成员函数可以重载;
  3. 类指针的用法与结构体指针相同;
  4. 类的成员可以是任意数据类型(类中枚举);
  5. 可以为类的成员指定缺省值(C++11标准);
  6. 类可以创建对象数组,就像结构体数组一样;
  7. 对象可以将参数传递给函数,一般传地址或传引用;
  8. 可以用new动态创建对象,用delete释放对象;
  9. 一般不直接访问(读和写)对象的成员,可以用成员函数;
  10. 对象一般不用memset()清空成员变量,可以写一个专门用来清空成员变量的成员函数;
  11. 对类和对象用sizeof()运算符意义不大,一般不用;
  12. 用结构体描述纯粹的数据,用类描述对象;
  13. 在类的声明中定义的函数都将自动成为内联函数,在类的声明之外定义的函数如果使用inline限定符,也是内联函数;
  14. 为了区分类的成员变量和成员函数的形参,把成员变量名加m_前缀或_后缀,如m_name或name_;
  15. 类的分文件编写。一般情况下,把声明类的代码放在头文件中,把成员函数定义的代码放在源文件中。

四、构造函数和析构函数

1.构造函数

构造函数:在创建对象时,自动的进行初始化工作。
语法:类名() {…}

  • 访问权限必须是public;
  • 函数名必须与类名相同;
  • 没有返回值,不写void;
  • 可以有参数,可以重载,可以有默认参数;
  • 创建对象时会自动调用一次,不能手工调用。

例:

#include <iostream>
using namespace std;

class supman
{
public:
	string m_name;
	int m_age;
	char m_memo[888];
	supman()  //声明并定义构造函数(不设置任何初始量)
	{
		m_name.clear(); m_age = 0; memset(m_memo, 0, sizeof m_memo);
		cout << "调用了supman()构造函数" << endl;
	}
	supman(string name)  //声明并定义构造函数(为成员姓名设置初始值)
	{
		m_name = name; m_age = 10; 
		cout << "调用了supman(string name)构造函数" << endl;
	}
	supman(string name, int age)  //声明并定义构造函数(为成员姓名和年龄设置初始值)
	{
		m_name = name; m_age = age; 
		cout << "调用了supman(string name,int age)构造函数" << endl;
	}
	void show()  //自我介绍
	{
		cout << " m_name:" << m_name << "    " << "m_age:" << m_age << endl;
	}
};

int main()
{
	supman man;          //① 创建超人对象,不设置任何初始值
	//supman man("小马哥");//② 创建超人对象,为成员姓名设置初始值
	//supman man("小马哥",8);//③ 创建超人对象,为成员姓名和年龄设置初始值
	man.show();
}

运行结果如下:

调用了supman()构造函数
 m_name:    m_age:0

C:\code\day\x64\Debug\day.exe (进程 33304)已退出,代码为 0。
按任意键关闭此窗口. . .
调用了supman(string name)构造函数
 m_name:小马哥    m_age:10

C:\code\day\x64\Debug\day.exe (进程 3596)已退出,代码为 0。
按任意键关闭此窗口. . .
调用了supman(string name,int age)构造函数
 m_name:小马哥    m_age:8

C:\code\day\x64\Debug\day.exe (进程 25756)已退出,代码为 0。
按任意键关闭此窗口. . .

注意事项:

  1. 如果没有提供构造/析构函数,编译器将提供空实现的构造/析构函数;
  2. 如果提供了构造/析构函数,编译器将不提供空实现的构造/析构函数;
  3. 创建对象的时候,如果重载了构造函数,编译器将根据实参匹配相应的构造函数。没有参数的构造函数也叫默认构造函数;
  4. 创建对象的时候如果没有实参的话,不要在后面添加圆括号,否则编译器将误以为是声明函数;(如果没有构造函数、构造函数没有参数、构造函数的参数都有默认参数)
  5. 在构造函数名后加括号和参数不是调用构造函数,而是创建匿名对象;
  6. 接受一个参数的构造函数允许使用赋值语法将对象初始化为一个值(可能会导致问题,不推荐);
  7. 以下两类代码有本质区别:
supman man  = supman("小马哥", 8);  //显示创建对象,调用一次构造函数和析构函数

supman man;  //创建对象man,调用一次构造函数和析构函数
man  = supman("小马哥", 8);   //创建匿名对象,然后给现有的对象赋值,又调用一次构造函数和析构函数
  1. 用new/delete创建/销毁对象时,也会调用构造/析构函数;
  2. 不建议在构造/析构函数中书写太多代码,可以调用成员函数;
  3. 除了初始化,不建议让构造函数做太多工作(做一些简单、只能成功不能失败的工作)
  4. C++11支持使用统一初始化列表;
supman man = {"小马哥", 8};
supman man  {"小马哥", 8};
supman* man =new  supman{"小马哥", 8};
  1. 如果类的成员也是类,创建对象的时候,先构造成员类;销毁对象的时候,先析构成员类。

2.析构函数

析构函数:在销毁对象前,自动的完成清理工作。
语法:~类名() {…}

  • 访问权限必须是public;
  • 函数名的前面必须加~;
  • 没有返回值,不写void;// ~supman() {…}
  • 没有参数,不能重载;
  • 销毁对象前只会自动调用一次,但是可以手工调用。

五、拷贝构造函数

用一个已存在的对象创建新的对象,不会调用(普通)构造函数,而是调用拷贝构造函数。
如果类中没有定义拷贝调用函数,编译器将会提供一个默认的拷贝构造函数,它的功能是把已存在的对象的成员变量赋值给新对象的成员变量。

1.创建新对象的语法

用一个已存在的对象创建创建新对象的语法:
类名 新对象名(已存在的对象名); 或 类名 新对象名 = 已存在的对象名;

2.拷贝构造函数的语法

语法:类名(const 类名& 对象名) {…}
注意:

  • 访问权限必须是public;
  • 函数名必须与类名相同;
  • 没有返回值,不写void;
  • 如果类中定义了拷贝构造函数,编译器将不提供默认的拷贝构造函数;
  • 值传递的方式调用函数时,如果实参为对象,会调用拷贝构造函数;
#include <iostream>
using namespace std;

class supman
{
public:
	string m_name;
	int m_age;

	supman()  //没有参数的普通构造函数
	{
		m_name.clear();
		m_age = 0;
		cout << "调用了supman()构造函数" << endl;
	}
	
	supman(const supman& gg)  //没有重载的拷贝构造函数(定义的默认拷贝构造函数)
	{
		m_name = "帅气的" + gg.m_name;
		m_age = gg.m_age + 1;  //等号右边一定要加上”gg.“,否则相当于自增
		cout << "调用了supman(const supman& gg)拷贝构造函数" << endl;
	}

	~supman()  //析构函数
	{
		cout << "调用了~supman()" << endl;
	}

	void show()
	{
		cout << " m_name:" << m_name << "    " <<
			"m_age:" << m_age << "    "<< endl;
	}
};

void funct(supman g)   //创建g对象
{
	g.show();
}

int main()
{
	supman man;  //创建man对象
	man.m_name = "小马哥"; man.m_age = 8;
	funct(man);
}

运行结果如下:

调用了supman()构造函数
调用了supman(const supman& gg)拷贝构造函数  //调用函数时,创建形参对象g的日志,调用了拷贝构造函数。
m_name:帅气的小马哥    m_age:9
调用了~supman()  //形参对象g销毁时,调用了析构函数
调用了~supman()  //对象man销毁时,调用析构函数

C:\code\day\x64\Debug\day.exe (进程 19452)已退出,代码为 0。
按任意键关闭此窗口. . .
  • 函数以值的方式返回对象时,不会调用拷贝构造函数(新版的VS中不会调用,Linux也不会,g++编译器做了优化)
#include <iostream>
using namespace std;

class supman
{
public:
	string m_name;
	int m_age;

	supman()  //没有参数的普通构造函数
	{
		m_name.clear();
		m_age = 0;
		cout << "调用了supman()构造函数" << endl;
	}
	
	supman(const supman& gg)  //没有重载的拷贝构造函数(定义的默认拷贝构造函数)
	{
		m_name = "帅气的" + gg.m_name;
		m_age = gg.m_age + 1;
		cout << "调用了supman(const supman& gg)拷贝构造函数" << endl;
	}

	~supman()  //析构函数
	{
		cout << "调用了~supman()" << endl;
	}

	void show()  //自我介绍
	{
		cout << " m_name:" << m_name << "    " <<
			"m_age:" << m_age << "    "<< endl;
	}
};

supman funct()
{
	supman man;
	man.m_name = "小马哥"; man.m_age = 8;
	cout << "对象man的地址:"<< & man << endl;
	return man;
}

int main()
{
	supman boy = funct();
	boy.show();
	cout << "对象boy的地址:" <<&boy << endl;
}

运行结果如下:

调用了supman()构造函数
对象man的地址:000000F24D9EF748
m_name:小马哥    m_age:8
对象boy的地址:000000F24D9EF748   //boy与man的地址相同,说明funct函数中创建的对象man没有被销毁,只是换个了变量名继续使用。这是比较科学的。
调用了~supman()

C:\code\day\x64\Debug\day.exe (进程 27060)已退出,代码为 0。
按任意键关闭此窗口. . .
  • 拷贝构造函数可以重载,可以有默认参数; 类名(…, const 类名& 对象名, …) {…}
  • 如果类中重载了拷贝构造函数却没有定义默认的拷贝构造函数,编译器也会提供默认的拷贝构造函数(它的功能是把已存在的对象的成员变量赋值给新对象的成员变量)。

六、浅拷贝和深拷贝

1.浅拷贝

背景案例:假设有指针a,指向堆区的内存,后来又有指针b,如果把指针a的值赋值给指针b,那么a和b将指向同一块内存。
针对此问题,引入类的内容中:假设指针a和b分别是对象A和对象B的两个成员,这样就会导致两个问题:
1)其中一个对象修改了指针指向的内存,就会影响另一个对象的内容;
2)我们一般会把释放内存的代码放到析构函数中,这样看起来比较安全,如果其中一个对象释放了内存,另一个对象的指针就会变成野指针。

2.深拷贝

深拷贝:如果有指针a指向一块内存,那么就重新分配一块相同大小的新内存,让指针b指向新内存,然后再把指针a指向的内存数据拷贝到新内存中。
这种方法比较彻底,解决了浅拷贝存在的问题,可独立操作,互不影响。
步骤:1.分配内存;2.拷贝数据。

七、初始化列表

1.执行过程

构造函数的执行可以分成两个阶段:初始化阶段和计算阶段。初始化阶段先于计算阶段。

  1. 初始化阶段:全部的成员都会在初始化阶段初始化,即使该成员没有出现在构造函数的初始化列表中。
  2. 计算阶段:一般是指用于执行构造函数体内的赋值操作。

构造函数除了参数列表和函数体之外,还可以有初始化列表。

2.语法

初始化列表的语法:类名(形参列表):成员一(值一),成员二(值二),成员三(值三),…成员n(值n) {…}

3.注意事项

  • 如果成员已经在初始化列表中,则不应该在构造函数中再次赋值;
  • 初始化列表的括号中可以是具体的值,也可以是构造函数的形参名,还可以是表达式;
	supman(string name, int age):m_name("帅气的"+name), m_age(age+1)  //没有重载的拷贝构造>函数(定义的默认拷贝构造函数)
	{
		//m_name = "帅气的" + name;
		//m_age = age + 1;
		cout << "调用了supman(string name, int age)构造函数" << endl;
	}
int main()
{
	supman boy("小马哥", 18);
}
  • 初始化列表与赋值有本质的区别,如果成员函数是类,使用初始化列表调用的是成员类的拷贝构造函数,而赋值则是先创建成员类的对象(将调用成员类的普通构造函数),然后再赋值
#include <iostream>
using namespace std;

class cgirl
{
public:
	string g_name;
	cgirl()  //没有参数的构造函数
	{
		g_name.clear();
		cout << "调用cgirl()构造函数" << endl;
	}
	cgirl(string name)  //定义成员名字的构造函数
	{
		g_name = name;
		cout << "调用cgirl(string name)构造函数" << endl;
	}
	cgirl(const cgirl& bb)  //默认拷贝构造函数
	{
		g_name = bb.g_name;
		cout << "调用cgirl(const cgirl&bb)拷贝构造函数" << endl;
}
};

class supman
{
public:
	string m_name;
	int m_age;
	cgirl m_girl;
	supman()
	{
		m_name.clear(); m_age = 0;
		cout << "调用了supman()构造函数" << endl;
	}
	supman(string name, int age, cgirl mz):m_name(name),m_age(age)  //设置三个参数的普通构造函数,其中对成员姓名和年龄进行初始化列表  
//也可以对mz引用(cgirl& mz)和初始化列表m_girl(mz),就会省略创建m_girl的过程,初始化和赋值是一步操作
	{
		m_girl.g_name = mz.g_name;  //对supman类中的成员变量(类)m_girl中的成员进行赋值
		cout << "调用了supman(string name, int age,cgirl mz)构造函数" << endl;
	}

	void show()  //自我介绍
	{
		cout << " m_name:" << m_name << "    " <<"m_age:" << m_age 
			<< "    "<<"girl:"<< m_girl.g_name<< endl;
	}
};

int main()
{
	cgirl girl("美羊羊");  //创建对象girl,并设置类girl的成员名字参数
	supman boy("小马哥", 18,girl); //创建对象boy,根据重载匹配相应的构造函数
	boy.show();
}

运行结果:

调用cgirl(string name)构造函数      //创建对象girl,调用构造函数
调用cgirl(const cgirl&bb)拷贝构造函数   //创建对象boy的过程中,选取匹配三参数的构造函数,由于girl是实参,
                   //  所以创建形参对象mz时,会调用cgirl类的拷贝构造函数,最终会显示该行日志。
调用cgirl()构造函数    //执行m_girl.g_name = mz.g_name;代码时,初始化supman类成员的m_girl时,调用的构造函数。
//用类创建对象的时候,先初始化构造函数的形参对象,然后再初始化类的成员
调用了supman(string name, int age,cgirl mz)构造函数  //执行cout语句
m_name:小马哥    m_age:18    girl:美羊羊    //执行boy.show()。

C:\code\day\x64\Debug\day.exe (进程 10828)已退出,代码为 0。
按任意键关闭此窗口. . .
  • 如果成员是类,初始化类表对性能略有提升;
  • 如果成员是常量或引用,必须使用初始化列表,因为常量和引用只能在定义的时候初始化;
const int m_age;//常量     //cgirl& m_girl;引用
...
supman(string name, int age, cgirl mz):m_name(name),m_age(age), m_girl(mz)
  • 如果成员是没有默认构造函数的类,则必须使用初始化列表;
  • 拷贝构造函数也可以有初始化列表;
  • 类的成员变量可以不出现在初始化类表中。

八、const修饰成员函数

在类的成员函数后面加const关键字,表示在成员函数中保证不会修改对象的成员变量。
例:void funct() const {…}

  1. mutable可以突破const限制,被mutable修饰的成员变量将永远处于可变的状态中,即使被const修饰的函数中,mutable也可以被修改;例:mutable int age;
  2. 非const成员函数可以调用const成员函数和非const成员函数;
  3. const成员函数不能调用非const成员函数;
  4. 非const对象可以调用const修饰的成员函数和非const修饰的成员函数;
  5. const对象只能调用const修饰的成员函数,不能调用非const修饰的成员函数。
    例:const supman boy;只能调用带有const的函数。
    注意:构造/析构函数不能加const关键词。

九、this指针

  • 如果类的成员函数中涉及多个对象,在这种情况下需要使用this指针。
  • this指针存放了对象的地址,它被作为隐藏参数传递给了成员函数,指向调用成员函数的对象(调用者对象)。

哪个对象调用了成员函数,就说明this指针指向了该对象。

#include <iostream>
using namespace std;

class supman
{
public:
	string m_name;
	int m_score;
	
	supman(const string& name, int age ):m_name(name),m_score(age)  //设置两个参数的普通构造函数,其中对成员姓名和分数进行初始化列表
	{
	}

	void show() const  //自我介绍
	{
		cout << "我是" << m_name << " " << ",最帅的男人" << endl;
	}

	const supman& pk(const supman& g) const
	{
		if (g.m_score > m_score) return g;
		return *this;
	}
};

int main()
{
	supman boy1("小马哥", 96), boy2("小雷哥", 99), boy3("小王哥", 98); //创建对象boy,根据重载匹配相应的构造函数
	const supman& boy = boy1.pk(boy2).pk(boy3);
	boy.show();
}

运行结果如下:

我是小雷哥 ,最帅的男人

C:\code\day\x64\Debug\day.exe (进程 1488)已退出,代码为 0。
按任意键关闭此窗口. . .
  • 每个成员函数(包括构造函数和析构函数)都有一个this指针,可以用它访问调用者对象的成员。(可以解决成员变量名与函数形参名相同的问题)
int aa;
void funct (int aa)
{
	aa = aa; //正确为:this->aa = aa;
//一般来说,成员变量的命名用m_为前缀或用_为后缀。
}```
  • this表示指针,解引用*this表示对象。
  • 如果在成员函数的括号后面加const,那么将不能通过this指针修改成员变量。

十、静态成员

1.组成

类的静态成员包括静态成员变量和静态成员函数。

2.语法

用static关键字把类的成员变量声明为静态,表示它在程序(不仅仅是对象)中是共享的;//static int m_age;
静态变量不会在创建对象的时候初始化,必须在程序的全局区用代码清晰的初始化(用范围解析运算符::);数据类型 类名::成员变量
静态成员使用类名加范围解析运算符::就可以访问,不需要创建新对象。

成员变量:先在定义成员变量时加static,之后在全局区写int supman::m_age;
成员函数:直接在成员函数前加static。

3.注意事项

1) 用静态成员可以实现多个对象之间的数据共享,比全局变量更安全。
2)如果把类的成员声明为静态的,就可以把它与类的对象独立开来(静态成员不属于对象)。相当于全局变量
3)静态成员在程序中只有一份(生命周期与程序运行周期相同,存放在静态存储区内),不论是否创建了类的对象,也不论创建了多少个类的对象。
4)静态成员函数只能访问静态成员,不能访问非静态成员。
5)静态成员函数没有this指针,因为它就不属于对象。
6)非静态成员函数可以访问静态成员。
7)私有静态成员变量在类外无法访问。

十一、简单对象模型

在C语言中,数据和处理数据的操作(函数)是分开的。也就是说,C语言本身没有支持数据和函数之间的关联性。
C++用类描述抽象数据类型(abstract data type,ADT),在类中定义了数据和函数,把数据和函数关联起来。
对象中维护了多个指针表,表中放了成员与地址的对应关系。
的方式

左边是对象的指针表,上图反映了成员和成员地址的对应关系。通过对象指针表可以找到对象成员的地址。对象的成员的内存空间不一定是连续的,但是,对象指针表的内存空间一定是连续的,并且指针表的大小是固定的。

C++类中有两种数据成员:nonstatic、static,三种函数成员:nonstatic、static、virtual。

  • 对象的内存大小包括:1)所有非静态数据成员的大小;2)由内存对齐而填补的内存大小;3)为了支持 virtual 成员而产生的额外负担。
  • 静态成员变量属于类,不计算在对象大小之内。
  • 成员函数是分开存储的,不论对象是否存在都占用存储空间,在内存中只有一个副本,也不计算在对象大小之内。
  • 用空指针可以访问没有用到 this 指针的非静态成员函数。

类中声明定义的成员变量,例如int age;当执行cout<<age;时,age在编译器是相当于this->age。
只有当输出常量时,空指针才可以访问非静态成员函数。例如成员函数为cout<<“小马哥”;main中为 类名* 指针名 = nulptr;指针名->成员函数名();

  • 对象的地址是第一个非静态成员变量的地址,如果类中没有非静态成员变量,编译器会隐含的增加一个1字节的占位成员。

十二、友元

1.原因

如果访问类的私有成员变量,调用类的公有成员函数是唯一的办法,而类的私有成员函数则无法访问。

2.分类

友元提供了另一种访问类的私有成员的方案。友元有三种:

  • 友元全局函数
  • 友元类
  • 友元成员函数

1)友元全局函数
在友元全局函数中,可以访问另一个类的所有成员。

例:

#include <iostream>
using namespace std;

class supman
{
	friend void funct();//友元全局函数
public:
	string m_name;
	
	supman(string name, int score):m_name(name),m_score(score)
	{	
	}

	void show1()   //自我介绍
	{
		cout << "我是" << m_name << " " << ",最帅的男人" << endl;
	}

private:
	int m_score;
	void show2()   //自我介绍
	{
		cout << "获得" << m_score << "分 "  << endl;
	}
};

void funct()//定义全局变量的函数
{
	supman boy("小马哥",98);
	cout << boy.m_score << endl;
	boy.show2();
}

int main()
{
	funct();
}

运行结果如下:

98
获得98分

C:\code\day\x64\Debug\day.exe (进程 3240)已退出,代码为 0。
按任意键关闭此窗口. . .

2)友元类
在友元类所有成员函数中,可以访问另一个类的所有成员。

#include <iostream>
using namespace std;

class supman
{
	friend class cgirl;  //声明友元类cgirl
public:
	string m_name;
	
	supman(string name, int score):m_name(name),m_score(score)
	{	
	}

	void show1()   //自我介绍
	{
		cout << "我是" << m_name << " " << ",最帅的男人" << endl;
	}

private:
	int m_score;
	void show2()   //自我介绍
	{
		cout << "获得" << m_score << "分 "  << endl;
	}
};

class cgirl
{
public:
	void funct(supman& boy)
	{
		cout  << boy.m_name << "是最帅的男人" << endl;
		cout << boy.m_score << "分好棒棒丫" << endl;
	}
};

void funct()
{
	supman man("小马哥", 98);
	cgirl girl;
	girl.funct(man);
}

int main()
{
	funct();
}

运行结果如下:

小马哥是最帅的男人
98分好棒棒丫

C:\code\day\x64\Debug\day.exe (进程 35728)已退出,代码为 0。
按任意键关闭此窗口. . .

注意

  • 友元关系不能被继承;
  • 友元关系是单向的,不具备交换性。
    若类B是类A的友元,类A不一定是类B的友元。B是类A的友元,类C是B的友元,类C不一定是类A的友元,要看类中是否有相应的声明。

3)友元成员函数
在友元类的某成员函数中,可以访问另一个类的所有成员。
以刚刚例子为说明,如果要把cgirl的某成员函数声明为supman类的友元,声明和定义的顺序如下:
第一步:class supman; //前置声明supman的类;
第二步:class cgirl {…}; //cgirl的定义,注意不要把成员函数的定义内容放进去,应该只写该成员函数的声明,定义内容会在下方书写。
第三步:class supman {…} //正常书写supman类的内容。
第四步:void cgirl::funct(supman& boy) {…} //友元成员函数的定义,也就是类cgirl中的成员函数的定义部分。这部分放在全局区的位置(放在类supman之后)。
第五步:把cgirl的成员函数声明为supman类的成员函数。//friend void cgirl::funct(supman& boy);

例:

#include <iostream>
using namespace std;

class supman;
class cgirl
{
public:
	void funct(const supman& boy);
};

class supman
{
	friend void cgirl::funct(const supman& boy);
public:
	string m_name;
	
	supman(string name, int score):m_name(name),m_score(score)
	{	
	}

	void show1()   //自我介绍
	{
		cout << "我是" << m_name << " " << ",最帅的男人" << endl;
	}

private:
	int m_score;
	void show2()   //自我介绍
	{
		cout << "获得" << m_score << "分 "  << endl;
	}
};

void cgirl::funct(const supman& boy)
{
	cout << boy.m_name << "是最帅的男人" << endl;
	cout << boy.m_score << "分好棒棒丫" << endl;
}

void funct()//定义全局变量的函数
{
	supman man("小马哥", 98);
	cgirl girl;
	girl.funct(man);
}

int main()
{
	funct();
}

运行结果如下:

小马哥是最帅的男人
98分好棒棒丫

C:\code\day\x64\Debug\day.exe (进程 32944)已退出,代码为 0。
按任意键关闭此窗口. . .
  • 28
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值