之前我们讨论过类成员的组成,尤其是成员函数,我们知道了定义一个类的时候,我们往往定义了:构造函数,析构函数,其他函数,以及友元函数(友元函数不是必须的)。

同时,我们知道了这样一个事情:在定义一个对象的时候:构造函数会被调用;对象被销毁的时候:会调用析构函数。友元函数提供给我们访问成员的另一种方式。

但这其中,会产生更多的细节。通过一些具体的细节,我们来感受一些类中的行为:

类声明如下:

 # include "iostream"
# ifndef STRNGBAD_H_
# define STRNGBAD_H_
class StringBad
{
private:
char *str;
int len;
static int num_strings; //= 0;//可见除了const 量之外,类内部成员是不能在内部赋初值的
public:
StringBad(const char * s);
StringBad();
~StringBad(); friend std::ostream & operator<<(std::ostream & os, const StringBad & st);
};
# endif

上述这个类声明中:

和通常一样:包含了构造函数,析构函数,友元函数;但这里需要强调的是 静态成员变量:num_strings。当我们使用StringBad类生成A,B,C....诸多类对象的时候,A.str,B.str,C.str....这些变量本质上地址是不同的。但是A.num_strings,B.num_strings,A.num_strings,地址是相同的。即:静态成员是属于类,而不是属于对象的。

我们看看这个类的定义:

 # include "cstring"
# include "strngbad.h" using std::cout; int StringBad::num_strings = ; StringBad::StringBad(const char*s)
{
len = std::strlen(s);
str = new char[len + ];
std::strcpy(str, s);
num_strings++;
cout << num_strings << ": \"" << str << "\" object created\n";
} StringBad::StringBad()
{
len = ;
str = new char[];
std::strcpy(str, "C++");
num_strings++;
cout << num_strings << ": \"" << str << "\" default created\n";
} StringBad::~StringBad()
{
cout << "\"" << str << "\" object created. ";
--num_strings;
cout << num_strings << "left\n";
delete[] str;
} std::ostream & operator<<(std::ostream & os, const StringBad & st)
{
os << st.str;//注意这里打印的是 str,如果不加str呢
return os;
}

关于这个类定义:我们注意这么几点:第6行进行了静态变量的初始化。注意,对num_strings 进行初始化的时候,StringBad::num_strings表明num_strings成员属于StringBad

问题:可以在类声明中进行初始化吗?

答:不可以,类声明只是说明需要为什么样的类型分配多少空间,但并不真正的分配空间,因此不能在声明中初始化(const除外)。

从这个类定义文件可以看出:无论是描述类成员函数,还是类成员变量.我们都要在前面描述其作用域!

new 和delete在动态内存分配中是十分重要的。但是要注意:在构造函数中使用了new[],在析构函数中必有delete[].

继续看调用文件:

 # include "iostream"
using std::cout;
# include "strngbad.h" void callme1(StringBad &);
void callme2(StringBad); int main()
{
using std::endl;
{
cout << "Starting an inner block.\n";
StringBad headline1("hello world!");
StringBad headline2("learning forever!");
StringBad sports("i love trvaling!");
cout << "headline1" << headline1 << endl;
cout << "headline12"<< headline2 << endl;
cout << "sports" << sports << endl;
callme1(headline1);
cout << "headline1" << headline1 << endl;
callme2(headline2);
cout << "headline2" << headline2 << endl;
cout << "Initialize one object to another:\n";
StringBad sailor = sports;
cout << "sailor: " << sailor << endl;
}
cout << "End of main()\n";
system("pause");
return ;
} void callme1(StringBad & rsb)
{
cout << "String passed by reference:\n";
cout << " \n" << rsb << "\"\n";
} void callme2(StringBad sb)
{
cout << "String passed by rvalue:\n";
cout << " \n" << sb << "\"\n";
}

在此,给出第19行代码和第21行代码的一些细节:

第19行代码,传递参数的行为是引用传递,21行为:值传递。

再次强调:值传递 和 值返回 函数的两个本质特征:1. 进行值传递的时候,复制实参的副本,使得形参为实参的副本;2. 值返回的时候,复制返回值的副本(并销毁该变量(因为栈中的变量生存周期为函数调用期)),对副本进行后续操作。

因此第21行的代码:在进行按值传递的时候,首先创建一个对象的副本。但在创建对象副本的时候,首先会调用构造函数,但是这个构造函数是谁呢?是之前类定义中的构造函数吗?如果是,显然这个创建副本的形式应该为:()或者(cha*),但问题是:这里是吗???显然不是,那是什么呢???其实为:B=A,即将已知的对象A赋值给临时对象B,这就如同第24行的代码。那么这样的初始化方式,调用哪个构造函数呢???其实,是一种叫做赋值构造函数,专门应对这种赋值初始化的操作。很明显,之前的声明和定义中并没有赋值构造函数。那么这个赋值构造函数只能由编译器产生。

终于知道为何开始要求我们采用()或者{}的初始化方式,而不是"="的初始化方式。因为通常的我们可能并没有显示的定义自己的赋值构造函数,这个时候由编译器产生一个这样的函数,可能会存在一定的风险。但如果我们不可避免会采用到=或者值传递创建函数的形式,我们应该显示的定义自己的赋值构造函数,使得我们的程序风险更低。(实际上,通常的定义一个显示赋值构造函数更保险)

总结:按值传递和按值返回对象的时候,都将调用赋值构造函数!2构造函数中创建一个显示赋值构造函数通常更保险

我们在此再次声明:“hello World!”表示一个地址而不是字符串。当我们定义:p = “hello Word!”,假如我们定义:q = p,那么:是否是将字符串P复制了一遍,并存到了q的地址呢?并不是,而是:p,q都指向了“hello world!”,而这个时候,“hello world! ”其实看起来更像地址。

c++入门之详细探讨类的一些行为的更多相关文章

  1. c++入门之再次探讨类属性

    精辟博文:https://blog.csdn.net/msdnwolaile/article/details/51923859(转载,仅供学习|!)

  2. c++ 入门之深入探讨拷贝函数和内存分配

    在c++入门之深入探讨类的一些行为时,说明了拷贝函数即复制构造函数运用于如下场景: 对象作为函数的参数,以值传递的方式传给函数. 对象作为函数的返回值,以值的方式从函数返回 使用一个对象给另一个对象初 ...

  3. JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式

    相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...

  4. Python编程从入门到实践笔记——类

    Python编程从入门到实践笔记——类 #coding=gbk #Python编程从入门到实践笔记——类 #9.1创建和使用类 #1.创建Dog类 class Dog():#类名首字母大写 " ...

  5. python入门学习:8.类

    python入门学习:8.类 关键点:类 8.1 创建和使用类8.2 使用类和实例8.3 继承8.4 导入类 8.1 创建和使用类   面向对象编程是最有效的软件编写方法之一.在面向对象编程中,你编写 ...

  6. discuz插件开发新手入门 超详细

    作为一个新手,目前也是刚刚玩转discuz的插件功能,好东西不敢独享,就拿出来大家一起分享入门的过程.现在网上很多关于discuz的插件教程都是很简单的教程,原因可能是这个东西是商业化的东西,本着分享 ...

  7. SpringBoot入门最详细教程

    monkey01 关注 2017.08.08 13:36* 字数 1479 阅读 34248评论 0喜欢 15 网上有很多springboot的入门教程,自己也因为项目要使用springboot,所以 ...

  8. SpringMVC札集(03)——基于注解的SpringMVC入门完整详细示例

    自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onL ...

  9. Python 3 快速入门 3 —— 模块与类

    本文假设你已经有一门面向对象编程语言基础,如Java等,且希望快速了解并使用Python语言.本文对重点语法和数据结构以及用法进行详细说明,同时对一些难以理解的点进行了图解,以便大家快速入门.一些较偏 ...

随机推荐

  1. c/c++ 智能指针 weak_ptr 使用

    智能指针 weak_ptr 使用 weak_ptr用途: 1,解决空悬指针问题 2,解决循环引用问题 weak_ptr特点:没有*操作和->操作 weak_ptr是不控制所指对象生存周期的智能指 ...

  2. Windows Server 2016-管理站点复制(一)

    可以使用Active Directory站点和服务管理单元来管理实现站点间复制拓扑的特定于站点的对象.这些对象存储在Active Directory域服务 (AD DS) 的站点容器中.同一个站点内的 ...

  3. Windows单机最大TCP连接数的问题

    本文和大家分享一下Windows下单机最大TCP连接数,因为在做Socket 编程时,我们经常会要问,单机最多可以建立多少个 TCP 连接,本文将介绍如何调整系统参数来调整单机的最大TCP连接数. W ...

  4. JavaScript -- 时光流逝(七):js中的全局函数

    JavaScript -- 知识点回顾篇(七):js中的全局函数 全局函数可用于所有内建的 JavaScript 对象. (1) encodeURI():把字符串编码为 URI. <script ...

  5. Shell编程基础知识(一)

    一.基本的运行Linux程序的3种方法: (1) 使文件具有可执行权限,直接运行文件.eg:  chmod a+x testfile.sh   ./testfile.sh (2) 直接调用命令解释器来 ...

  6. Nginx location配置详解

    上一篇博客Nginx配置详解已经说过了nginx 的基本配置情况,今天来详细讲述一下nginx的location的配置原则, location是根据Uri来进行不同的定位,location可以把网站的 ...

  7. Leancloud+Valine打造Hexo个人博客极简评论系统

    以下配置是基于Next主题6.1.0版本 效果见个人博客的最下方评论. Leancloud配置 首先访问Leancloud官网https://leancloud.cn/ 有Github账号的小伙伴可以 ...

  8. 【Linux基础】awk命令

    1.awk命令说明 (1)awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 (2)awk处理过程:  依次对每一行进行处理,然后输出 ...

  9. 简单理解Vue中的nextTick

    Vue中的nextTick涉及到Vue中DOM的异步更新,感觉很有意思,特意了解了一下.其中关于nextTick的源码涉及到不少知识,很多不太理解,暂且根据自己的一些感悟介绍下nextTick. 一. ...

  10. nginx入门与实战

    网站服务 想必我们大多数人都是通过访问网站而开始接触互联网的吧.我们平时访问的网站服务 就是 Web 网络服务,一般是指允许用户通过浏览器访问到互联网中各种资源的服务. Web 网络服务是一种被动访问 ...