白话C++系列(9)

精彩的类外定义

类内定义

问题:什么是类内定义?

将成员函数的函数体写在类的内部的方式称为类内定义。比如下面的Student的类,我们可以看到,在定义成员函数的时候,包括每个成员函数用于实现的函数体,都在类的内部。

类内定义与内联函数的关系

类内定义的成员函数,编译器会将其优先编译为内联函数,但是对于复杂的成员函数无法编译成内联函数的,就编译成普通的函数。

类外定义

所谓类外定义是指成员函数的函数体写在类的外面。具体来讲,类外定义又分为以下两种形式:

所谓同文件类外定义,是指成员函数虽然定义在类的外面,但是其定义与类的定义在同一个文件当中。如下面的例子:

我们新建一个文件,文件名为Car.cpp,然后在这个文件中定义一个Car的类,定义的时候先写上汽车这个类的定义(class Car),并申明相应的成员函数,但是成员函数的实现或者说成员函数体的定义也写在这个文件中。那么成员函数既然写在了类的外面,我们就要标示出这个成员函数不是普通的函数,而是属于Car这个汽车的函数,我们就需要在这个函数的前面用这个类名再加上::标记出这个函数是属于这个类的。

下面介绍分文件类外定义,如果说同文件类外定义算是游击队的话,那分文件诶外定义可以算是正规军了。几乎所有的c++项目,但凡是专业一点的c++程序员都会将类的定义分文件来完成,这样做有诸多好处,我们会在后续的课程中来给大家逐步讲解。下面来看一个例子来给大家说明分文件类外定义的写法。

分文件定义的时候,我们需要定义一个.h文件(头文件),类名建议与文件名写成一致。如下是一个Car.h头文件,在头文件中我们申明了类中的所有的数据成员和成员函数,在另外一个文件(Car.cpp)中,我们把所有的成员函数进行定义,定义的方式跟以前一样,最为关键的一点是需要将其头文件(Car.h)包含到Car.cpp中,如果没有这样的包含,Car.cpp将无法找到其相应的申明。

代码实践

题目描述:

定义一个Teacher类,要求分别采用同文件类外定义和分文件类外定义的方式完成,具体要求如下:

数据成员:

名字

年龄

性别

成员函数:

数据成员的封装函数

授课teach

类内定义方式:

#include<iostream>
#include<stdlib.h>
#include<string>

usingnamespacestd;

/*  ************************************************************************/

/*  定义一个Teacher类,要求分别采用同文件类外定义和分文件类外定义的方式完成,具体要求如下:
/*   数据成员:
/*       名字
/*       年龄
/*       性别
/*   成员函数:
/*       数据成员的封装函数
/*       授课teach
/*  ************************************************************************/

classTeacher
{
public:
    voidsetName(string _name);
    stringgetName();
    voidsetGender(string _gender);
    stringgetGender();
    voidsetAge(int _age);
    intgetAge();
    void teach();

private:
    stringm_strName;
    stringm_strGender;
    intm_iAge;
};

voidTeacher::setName(string_name)
{
    m_strName = _name;
}
stringTeacher::getName()
{
    returnm_strName;
}
voidTeacher::setGender(string_gender)
{
    m_strGender = _gender;
}
stringTeacher::getGender()
{
    returnm_strGender;
}

voidTeacher::setAge(int_age)
{
    m_iAge = _age;
}
intTeacher::getAge()
{
    returnm_iAge;
}
voidTeacher :: teach()
{
    cout<<"现在开始上课....."<<endl;
}

int main()
{
    Teacher t;
    t.setName("孔子");
    t.setGender ("男");
    t.setAge(30);
    cout<<t.getName() <<" "<<t.getGender() <<" "<<t.getAge() <<" "<<endl;
    t.teach();
    system("pause");
    return 0;
}

运行结果:

类外定义方式:

程序框架如下

头文件(Teacher.h)

#include<string>
usingnamespacestd;
classTeacher
{
public:
    voidsetName(string _name);
    stringgetName();
    voidsetGender(string _gender);
    stringgetGender();
    voidsetAge(int _age);
    intgetAge();
    void teach();

private:
    stringm_strName;
    stringm_strGender;
    intm_iAge;
};

源文件:

#include"Teacher.h"
#include<iostream>
#include<stdlib.h>

usingnamespacestd;

/*  ************************************************************************/

/*  定义一个Teacher类,要求分别采用同文件类外定义和分文件类外定义的方式完成,具体要求如下:
/*   数据成员:
/*       名字
/*       年龄
/*       性别
/*   成员函数:
/*       数据成员的封装函数
/*       授课teach
/*  ************************************************************************/

voidTeacher::setName(string_name)
{
    m_strName = _name;
}
stringTeacher::getName()
{
    returnm_strName;
}
voidTeacher::setGender(string_gender)
{
    m_strGender = _gender;
}
stringTeacher::getGender()
{
    returnm_strGender;
}

voidTeacher::setAge(int_age)
{
    m_iAge = _age;
}
intTeacher::getAge()
{
    returnm_iAge;
}
voidTeacher :: teach()
{
    cout<<"现在开始上课....."<<endl;
}

int main()
{
    Teacher t;
    t.setName("孔子");
    t.setGender ("男");
    t.setAge(30);
    cout<<t.getName() <<" "<<t.getGender() <<" "<<t.getAge() <<" "<<endl;
    t.teach();
    system("pause");
    return 0;
}

运行结果:

时间: 2024-08-07 02:10:37

白话C++系列(9)的相关文章

白话C++系列(10)--对象的生离死别

对象的生离死别 思考:实例化的对象是如何在内存中存储的? 思考:类中的代码又是如何存储的? 思考:数据和代码之间又有怎样的关系呢? 带着这些问题,先学习一下对象的结构 对象结构 要想为大家说清对象是如何存储的,就必须先为大家介绍一下内存中按照用途被划分的5个区域. 栈区的特点是内存由系统进行控制,无论是分配还是回收都不需要程序员关心: 如果我们使用new来分配一段内存,那么这段内存会分配在堆区,最后我们自己必须用delete回收这段内存: 全局区用来存储全局变量和静态变量: 常量区用来存放一些字

白话C++系列(7)

初始字符串类型 思考如下一个问题:我们平时在编码过程中,适用频繁而操作又比较繁琐的数据都有哪些呢? 对于基本数据类型(int.char.float.double.bool),我们虽用的比较频繁,但操作起来还是比较方便的,基本令人满意.只有char数组,也就是通常所说的字符串,我们平时用的比较频繁,但操作上却缺乏一种简单有效的手段,往往只能用一系列的函数来应付,如strlen.strcat.strcmp.strcpy.strncmp.strncpy等,用得多了就觉得特别麻烦,有时会令人抓狂.为了解

白话C++系列(8)

属性封装的艺术 数据的封装 下面看一个例子,例子中定义了一个学生的类,类中含有两个数据成员,一个是姓名,一个是年龄 上面的代码给人一种相当亲切,有一种似曾相识的感觉,那是因为之前我们一直都是这么用的,而且用的也很爽.但是,这样用是有问题的,最大的问题是它违背了面向对象的知道思想. 那么面向对象的基本思想是什么呢? 面向对象的核心就是以对象为中心,具体来说,就是要以谁做什么来表达程序的逻辑,体现在代码层面上,就是将所有的数据操作转换为成员函数的调用.换句话说,对象在程序中的所有行为都通过调用自己的

白话C++系列(5)

C++内存管理 什么是内存管理? 思考:内存的本质是什么?---->资源 思考:谁掌管内存资源? ---->操作系统 思考:我们能做什么?  ---->申请/归还 申请/归还内存资源就是内存管理 C++中如何进行内存的申请和释放? 申请  --->使用运算符new 释放  --->使用运算符delete 即: 申请内存:int *p = new int; 释放内存:  delete p; 这样就申请和释放一个内存或是某一种类型的内存 思考:如何申请和释放块内存呢? int *

白话C++系列(4)

C++函数新特性 函数参数默认值 有如下函数声明: voidfun(int i, int j = 10, int k = 20);√ voidfun(int i, int j = 10, int k) ;X 注意:有默认参数值的参数必须在参数表的最右端 在函数声明时可以带上参数默认值,而在定义时,不建议带上参数默认值.如果在函数定义的时候也协商函数参数默认值,则实际编译时,有的编译器能够编译通过,而有的编译器编译不会通过. 示例: #include <iostream> #include<

白话LINQ系列2---以代码演进方式学习LINQ必备条件

今天我们通一个简单的示例代码的演进过程,来学习LINQ必备条件:隐式类型局部变量:对象集合初始化器:委托:匿名函数:lambda表达式:扩展方法:匿名类型.废话不多说,我们直接进入主题. 一.实现要求 1.获取全部女生: 2.对满足要求的结果按年龄排序: 3.获取结果的前两名: 4.对获取结果计算平均年龄: 5.输出结果信息,包含姓名.性别.年龄: 说明:学生类为Student(包含学生完整信息),输出结果类为:StudentInfo(包含我们关心的信息,后面将演示它是如何消失的).在此我们不讨

排序算法系列——插入排序

记录学习点滴,菜鸟成长记 接触算法是研究生期间做项目时,需要编写一些诸如GA.QGA的时候,第一次使用“排序”还是用的Java自带的Comparator接口.后来买了<算法导论>来看,发现果然所有知识都是有专业壁垒的,简单的一个问题尽然蕴藏着如此多的思想,发现此简直欣喜无比,遂决定要好好研究研究.只有深入后才发现,原来算法的不仅仅是按照逻辑顺序写个程序那么简单,好的算法要考虑到方方面面,最简单的时间复杂度就够我学习很长时间了. 将自己学习排序算法的一些理解和感悟记录于此,方便自己温故而知新.

MongoDB资料汇总(转)

原文:MongoDB资料汇总 上一篇Redis资料汇总专题很受大家欢迎,这里将MongoDB的系列资料也进行了简单整理.希望能对大家有用. 最后更新时间:2013-04-22 1.MongoDB是什么 MongoDB介绍PPT分享 MongoDB GridFS介绍PPT两则 初识 MongoDB GridFS MongoDB GridFS 介绍 一个NoSQL与MongoDB的介绍PPT MongoDB:下一代MySQL? 写给Python程序员的MongoDB介绍 又一篇给Python程序员的

大白话讲解Promise(一)

去年6月份, ES2015正式发布(也就是ES6,ES6是它的乳名),其中Promise被列为正式规范.作为ES6中最重要的特性之一,我们有必要掌握并理解透彻.本文将由浅到深,讲解Promise的基本概念与使用方法. ES6 Promise 先拉出来遛遛 复杂的概念先不讲,我们先简单粗暴地把Promise用一下,有个直观感受.那么第一个问题来了,Promise是什么玩意呢?是一个类?对象?数组?函数? 别猜了,直接打印出来看看吧,console.dir(Promise),就这么简单粗暴. 这么一