在開始类的编写之前我们依旧须要回想整理一下前面所说的内容,(前面尽管是一个自己定义数据类型的实现过程,可是内容有点繁杂).

先看一段代码:

/** @file calssStruct.cpp */
/** Member Functions for Class point */
#include <cmath> // for sqrt and atan using namespace std; struct point
{
point()
: x_(0.0), y_(0.0)
{}
point(double x, double y)
: x_(x), y_(y)
{}
point(point const& pt)
: x_(pt.x_), y_(pt.y_)
{} /// Distance to the origin.
double distance()
{
return std::sqrt(x*x + y*y);
}
/// Angle relative to x-axis.
double angle()
{
return std::atan2(y, x);
} /// Add an offset to x and y.
void offset(double off)
{
offset(off, off);
}
/// Add an offset to x and an offset to y
void offset(double xoff, double yoff)
{
x = x + xoff;
y = y + yoff;
} /// Scale x and y.
void scale(double mult)
{
this->scale(mult, mult);
}
/// Scale x and y.
void scale(double xmult, double ymult)
{
this->x = this->x * xmult;
this->y = this->y * ymult;
}
double x_;
double y_;
};

上面代码中有构造函数,有成员函数,有数据成员.我们如今须要分析一个在上面和之前的成员函数中出现的一个this引用.

在C++中,每一个成员函数都有一个隐含的形參this,当成员函数被调用时,其对象本身就被编译器作为实參隐式传入.在成员函数中能够使用*this表达式訪问该对象.在C++语法中点操作符比星操作符优先级高,因此须要使用圆括号(如(*this).x).还有一种等价的调用时使用”箭头”,即是this->x.

可是事实上编译器能够自己主动识别那些是成员名字,所以this->是可选的,即是能够省略的.可是有时候为了代码清晰总是加上它.而一些程序猿则为了表明是数据成员,有时候往往在数据成员名称前面加上前缀,或者在后面加上后缀.我倾向于后缀,如上面的代码.

关于构造函数,初始化时类和内置类型的一个重要差别,假设定义一个内置类型而不提供初始化序列,那么它的值就是无意义的;而定义类的对象时,该对象一定会被构造器初始化,因此总有机会初始化数据成员.

虽然构造函数的冒号后面的初始化列表是可选的,可是建议总是加上.

依据数据成员的类型是类或者内置类型,编译器会做出不同的处理.每一个成员的初始化表有以下的三种情况:

以下再来一个构造函数的验证代码:

/** @file constructFun.cpp */
/** Visual Constructors */
#include <iostream>
#include <ostream> using namespace std; struct demo
{
demo() : x_(0) { std::cout << "default constructor\n"; }
demo(int x) : x_(x) { std::cout << "constructor(" << x << ")\n"; }
demo(demo const& that)
: x_(that.x_)
{
std::cout << "copy constructor(" << x_ << ")\n";
}
int x_;
}; demo addone(demo d)
{
++d.x_;
return d;
} int main()
{
demo d1;
demo d2(d1);
demo d3(42);
demo d4(addone(d3));
}

结果例如以下:

可是是否是学习到这里我们就把构造函数什么的搞明确了呢,以下我们来測试一下,先看代码:

/** @file Test_Construct.cpp */
/** Mystery Program */
#include <iostream>
#include <ostream> using namespace std;
struct point
{
point()
: x_(0.0), y_(0.0)
{
cout << "default constructor\n";
}
point(double x, double y)
: x_(x), y_(y)
{
cout << "constructor(" << x << ", " << y << ")\n";
} double x_;
double y_;
}; int main()
{
point pt();
}

你觉得这个编译后会输出什么呢?是default constructor么?

可是你错了……这就是输出:

即是根本未定义变量,编译器觉得你编写了一个无參数的返回值为point的名字是pt的函数声明!

假设你不理解那么把point改成int,如今是intpt();这样是不是就更像一个函数声明了呢.可是假设要定义一个变量应该怎么样的呢?

是 point pt;即是不带括号这个时候调用了默认的无參数构造函数初始化.

所以在定义变量的时候注意哪些括号是必须的,不然非常可能就会误导编译器将你的所谓的”变量声明”当成函数声明.

练习项目一

身体质量指数BMI小程序

学习了那么多能够做个小项目练习一下了.要计算BMI须要知道一个人的身高体重,BMI的计算公式是体重/(身高^2),结果是一个无单位的值.如今的任务是编写一个程序,使其能够读取记录,打印记录并计算一些统计值.该程序以请求一个BMI上极限開始,仅打印BMI值大雨或等于此极限值的记录,每条记录包括姓名(能够有空格),体重,身高(单位cm),以及性别(M或F,不限大写和小写).读取完每一个人的记录后要马上打印该记录的BMI值,手机全部的记录后,基于数据打印两个表------男性一个,女性一个.在BMI值后面用*标记超过界限的BMI记录.并打印BMI的均值和中值.

当中的一个演示样例代码例如以下.

/** @file BMI_Again.cpp */
/** New BMI Program */
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <ios>
#include <iostream>
#include <istream>
#include <limits>
#include <locale>
#include <ostream>
#include <string>
#include <vector> using namespace std; /// Compute body-mass index from height in centimeters and weight in kilograms.
int compute_bmi(int height, int weight)
{
return static_cast<int>(weight * 10000 / (height * height) + 0.5);
} /// Skip the rest of the input line.
void skip_line(istream& in)
{
in.ignore(numeric_limits<int>::max(), '\n');
} /// Represent one person’s record, storing the person’s name, height, weight,
/// sex, and body-mass index (BMI), which is computed from the height and weight.
struct record
{
record() : height_(0), weight_(0), bmi_(0), sex_('?'), name_()
{} /// Get this record, overwriting the data members.
/// Error-checking omitted for brevity.
/// @return true for success or false for eof or input failure
bool read(istream& in, int num)
{
cout << "Name " << num << ": ";
string name;
if (not getline(in, name))
return false; cout << "Height (cm): ";
int height;
if (not (in >> height))
return false;
skip_line(in); cout << "Weight (kg): ";
int weight;
if (not (in >> weight))
return false;
skip_line(in); cout << "Sex (M or F): ";
char sex;
if (not (in >> sex))
return false;
skip_line(in);
sex = toupper(sex, locale()); // Store information into data members only after reading
// everything successfully.
name_ = name;
height_ = height;
weight_ = weight;
sex_ = sex;
bmi_ = compute_bmi(height_, weight_);
return true;
} /// Print this record to @p out.
void print(ostream& out, int threshold)
{
out << setw(6) << height_
<< setw(7) << weight_
<< setw(3) << sex_
<< setw(6) << bmi_;
if (bmi_ >= threshold)
out << '*';
else
out << ' ';
out << ' ' << name_ << '\n';
} int height_; ///< height in centimeters
int weight_; ///< weight in kilograms
int bmi_; ///< Body-mass index
char sex_; ///< 'M' for male or 'F' for female
string name_; ///< Person’s name
}; /** Print a table.
* Print a table of height, weight, sex, BMI, and name.
* Print only records for which sex matches @p sex.
* At the end of each table, print the mean and median BMI.
*/
void print_table(char sex, vector<record>& records, int threshold)
{
cout << "Ht(cm) Wt(kg) Sex BMI Name\n"; float bmi_sum(0);
long int bmi_count(0);
vector<int> tmpbmis; // store only the BMIs that are printed
// in order to compute the median
for (vector<record>::iterator iter(records.begin());
iter != records.end();
++iter)
{
if (iter->sex_ == sex)
{
bmi_sum = bmi_sum + iter->bmi_;
++bmi_count;
tmpbmis.push_back(iter->bmi_);
iter->print(cout, threshold);
}
} // If the vectors are not empty, print basic statistics.
if (bmi_count != 0)
{
cout << "Mean BMI = "
<< setprecision(1) << fixed << bmi_sum / bmi_count
<< '\n'; // Median BMI is trickier. The easy way is to sort the
// vector and pick out the middle item or items.
sort(tmpbmis.begin(), tmpbmis.end());
cout << "Median BMI = ";
// Index of median item.
int i(tmpbmis.size() / 2);
if (tmpbmis.size() % 2 == 0)
cout << (tmpbmis.at(i) + tmpbmis.at(i-1)) / 2.0 << '\n';
else
cout << tmpbmis.at(i) << '\n';
}
} /** Main program to compute BMI. */
int main()
{
locale::global(locale(""));
cout.imbue(locale());
cin.imbue(locale()); vector<record> records;
int threshold; cout << "Enter threshold BMI: ";
if (not (cin >> threshold))
return EXIT_FAILURE;
skip_line(cin); cout << "Enter name, height (in cm),"
" and weight (in kg) for each person:\n";
record rec;
while (rec.read(cin, records.size()+1))
{
records.push_back(rec);
cout << "BMI = " << rec.bmi_ << '\n';
} // Print the data.
cout << "\n\nMale data\n";
print_table('M', records, threshold);
cout << "\nFemale data\n";
print_table('F', records, threshold);
}

执行结果例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3Vvb2w=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

可是看到上面的这个函数:

你是否认为函数參数传递应该是const类型更合适呢,我们改动了一下,測试,发现,,,不行,出现了错误.可是显然应该是const类型的引用传递.那怎么实现呢.

应该记得在每一个成员函数的内部都有一个this隐藏參数,上面的代码段中,print_table调用print成员函数,可是经过改动,this引用了一个const对象.虽然你知道print函数不会改动不论什么的数据成员,可是编译器不知道,因此你须要让编译器知道,怎么做呢,仅仅要在函数头和函数体之间加上一个const修饰符就可以.例如以下:

而一个通用的规则是,为全部的不改动成员变量的函数加入const修饰符,它确保程序在有const对象的时候就能够调用成员函数.

C++基础学习教程(六)----类编写的前情回想以及项目实战(1)的更多相关文章

  1. 《ASP.NET Core应用开发入门教程》与《ASP.NET Core 应用开发项目实战》正式出版

    “全书之写印,实系初稿.有时公私琐务猬集,每写一句,三搁其笔:有时兴会淋漓,走笔疾书,絮絮不休:有时意趣萧索,执笔木坐,草草而止.每写一段,自助覆阅,辄摇其首,觉有大不妥者,即贴补重书,故剪刀浆糊乃不 ...

  2. salesforce 零基础学习(六十八)http callout test class写法

    此篇可以参考: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restfu ...

  3. C++基础学习教程(七)----类编写及类的两个特性解析---&gt;多态&amp;继承

    类引入 到眼下为止我们所写的自己定义类型都是keywordstruct,从如今起我们将採用class方式定义类,这样的方式对于学习过其它高级语言包含脚本(Such as Python)的人来说再熟悉只 ...

  4. Java 从基础到进阶学习之路---类编写以及文档凝视.

    Java之前在学习过,基础知识还没有忘光,并且这些高级语言实在是太像,所以那些数据类型,或者循环控制流,以及标准设备等等就直接略过不说了. 只是一些重大概念会穿插在文章的介绍中. So,这些文章适合于 ...

  5. C++基础学习教程(八)

    转载请注明出处:http://blog.csdn.net/suool/article/details/38300117 引入 在进行下一步的学习之前,我们须要厘清几个概念. RAII 首先介绍一个编程 ...

  6. CSS学习笔记六:写原生导航栏

    因为刚开始学习CSS时,只了解了一些基本样式,然后就跑去学习bootstrap.bootstrap是个不错的东西,挺好玩,起码让你写界面写的轻轻松松,几行引入代码,再来个复制粘贴就解决了,而且boot ...

  7. C++基础学习教程(一)

    開始自己的C++复习进阶之路. 声明: 这次写的博文纯当是一个回想复习的教程.一些非常基础的知识将不再出现.或者一掠而过,这次的主要风格就是演示样例代码非常多~~~ 全部代码在Ubuntu 14.04 ...

  8. webpack从0到1超详细超基础学习教程

    概念 自己是一个一听到webpack就头大,看着一堆不知道那是什么玩意的东西总觉得自己做好前端就行了,但是在使用vue-cli的时候总觉得要改其中的一些东西进行项目初始化的时候能够更好使用!所以想要根 ...

  9. Python基础学习(六)

    前几天一直在练手廖雪峰老师的python课程,接下来继续学习,由于面向对象编程这一课相对理论便不在此练手,直接上手面向对象高级编程. 一.使用 __slots__ 一般情况下一个class是可以绑定一 ...

随机推荐

  1. Sutherland-Hodgeman多边形裁剪

    原文地址:http://course.cug.edu.cn/cugFirst/computer_graphics/class/course/3-3-1-a.htm

  2. 人脸识别中的Procruster analysis应用

    本文中,我们通过Procrustes analysis来处理特征点,Procrustes analysis算法可以参考:http://en.wikipedia.org/wiki/Procrustes_ ...

  3. CSS3动画的回调处理

    我们在做js动画的时候,很多时候都需要做回调处理,如在一个动画完成后触发一个事件.一个动画完成后执行另外一个动画等等,但在使用CSS3动画时能不能捕获到运动的状态做回调处理呢? CSS3动画也是可以做 ...

  4. 汇总c#.net常用函数和方法集

    1.DateTime 数字型 System.DateTime currentTime=new System.DateTime(); 1.1 取当前年月日时分秒 currentTime=System.D ...

  5. 使用Java语言开发微信公众平台(八)——自定义菜单功能

    随着上一篇文章的结束,我们已经实现了所有消息的类型的回复功能.今天,我们来学习更加高大上,也更加重要的自定义菜单功能. 一.了解自定义菜单 自定义菜单是微信公众平台最常用也是最重要的功能之一.根据微信 ...

  6. 利用样式——android2.3实现android4.0风格的edittext

    先看效果: 思路:在源码里找到4.0风格的图片作为背景,xml文件定义点击时候边框变化 步骤: ①.在F:\sdk\sdk\platforms\android-14\data\res\drawable ...

  7. Android -- 在xml文件中定义drawable数组

    Xml <string-array name="images"> <item>@drawable/image1</item> <item& ...

  8. Javascript 的模块化编程及加载模块【转载+整理】

    http://www.ruanyifeng.com/blog/2012/10/javascript_module.html 本文内容 引入 模块化 最初写法 对象写法 立即执行函数写法 放大模式 宽放 ...

  9. Python MySQLdb模块连接操作mysql数据库实例_python

    mysql是一个优秀的开源数据库,它现在的应用非常的广泛,因此很有必要简单的介绍一下用python操作mysql数据库的方法.python操作数据库需要安装一个第三方的模块,在http://mysql ...

  10. javascript链式语法

    因为 jQuery 库的缘故,链式语法在前端界变得非常流行.实际上这是一种非常容易实现的模式.基本上,你只需要让每个函数返回 'this',这样其他函数就可以立即被调用.看看下面的例子. var bi ...