当前位置: 首页 > news >正文

ssh网站开发公司品牌宣传

ssh网站开发,公司品牌宣传,建设网站比较好的公司排名,建设管理网站首页本文为 C 学习笔记,参考《Sams Teach Yourself C in One Hour a Day》第 8 版、《C Primer》第 5 版、《代码大全》第 2 版。 面向对象编程有四个重要的基础概念:抽象、封装、继承和多态。本文整理 C 中类与对象的基础内容,涉及抽象和封装两个…

本文为 C++ 学习笔记,参考《Sams Teach Yourself C++ in One Hour a Day》第 8 版、《C++ Primer》第 5 版、《代码大全》第 2 版。

面向对象编程有四个重要的基础概念:抽象封装继承多态。本文整理 C++ 中类与对象的基础内容,涉及抽象封装两个概念。《C++基础-继承》一文讲述继承概念。《C++基础-多态》一文讲述多态概念。这些内容是 C++ 中最核心的内容。

抽象

抽象是一种忽略个性细节、提取共性特征的过程。当用“房子”指代由玻璃、混凝土、木材组成的建筑物时就是在使用抽象。当把鸟、鱼、老虎等称作“动物”时,也是在使用抽象。

基类是一种抽象,可以让用户关注派生类的共同特性而忽略各派生类的细节。类也是一种抽象,用户可以关注类的接口本身而忽视类的内部工作方式。函数接口、子系统接口都是抽象,各自位于不同的抽象层次,不同的抽象层次关注不同的内容。

抽象能使人以一种简化的观点来考虑复杂的概念,忽略繁琐的细节能大大降低思维及实现的复杂度。如果我们在看电视前要去关注塑料分子、琉璃分子、金属原子是如何组成一部电视机的、电与磁的原理是什么、图像是如何产生的,那这个电视不用看了。我们只是要用一台电视,而不关心它是怎么实现的。同理,软件设计中,如果不使用各种抽象层次,那么这一堆代码将变得无法理解无法维护甚至根本无法设计出来。

封装

抽象是从一种高层的视角来看待一个对象。而封装则是,除了那个抽象的简化视图外,不能让你看到任何其他细节。简言之,封装就是隐藏实现细节,只让你看到想给你看的。

在程序设计中,就是把类的成员(属性和行为)进行整合和分类,确定哪些成员是私有的,哪些成员是公共的,私有成员隐藏,公共成员开放。类的用户(调用者)只能访问类的公共接口。

1. 类与对象

// 类:人类
class Human
{
pubilc:// 成员方法:void Talk(string textToTalk);   // 说话void IntroduceSelf();           // 自我介绍private:// 成员属性:string name;                    // 姓名string dateOfBirth;             // 生日string placeOfBirth;            // 出生地string gender;                  // 性别...
};// 对象:具体的某个人
Human xiaoMing;
Human xiaoFang;

对象是类的实例。语句 Human xiaoMing;int a; 本质上并无不同,对象和类的关系,等同于变量和类型的关系。

不介意外部知道信息使用 public 关键字限定,需要保密的信息使用 private 关键字限定。

2. 构造函数

2.1 构造函数

构造函数在创建对象时被调用。执行初始化操作。

  1. 构造函数名字与类名相同
  2. 构造函数无返回值
  3. 构造函数可以重载,一个类可有多个构造函数
  4. 构造函数不能被声明为 const,因为一个 const 对象也是通过构造函数完成初始化的,构造函数完成初始化之后,const 对象才真正取得"常量"属性。

构造函数形式如下:

class Human
{
public:Human();    // 构造函数声明
};Human::Human()  // 构造函数实现(定义)
{...
}

2.2 默认构造函数

可不提供实参调用的构造函数是默认构造函数,包括如下两种:
1) 不带任何函数形参的构造函数是默认构造函数
2) 带有形参但所有形参都提供默认值的构造函数也是默认构造函数,因为这种既可以携带实参调用,也可以不带实参调用

2.3 合成的默认构造函数

当用户未给出任何构造函数时,编译器会自动生成一个构造函数,叫作合成的默认构造函数,此函数对类的数据成员初始化规则如下:
1) 若数据成员存在类内初始化值,则用这个初始化值来初始化数据成员
2) 否则,执行默认初始化。默认值由数据类型确定。参"C++ Primer 5th"第 40 页

下面这个类因为没有任何构造函数,所以编译器会生成合成的默认构造函数:

class Human
{
pubilc:// 成员方法:void Talk(string textToTalk);   // 说话void IntroduceSelf();           // 自我介绍private:// 成员属性:string name;                    // 姓名string dateOfBirth;             // 生日string placeOfBirth;            // 出生地string gender;                  // 性别
};

2.4 参数带默认值的构造函数

函数可以有带默认值的参数,构造函数当然也可以。

class Human
{
private:string name;int age;public:// overloaded constructor (no default constructor)Human(string humansName, int humansAge = 25){name = humansName;age = humansAge;...};

可以使用如下形式的实例化

Human adam("Adam"); // adam.age is assigned a default value 25
Human eve("Eve, 18); // eve.age is assigned 18 as specified

2.5 带初始化列表的构造函数

初始化列表是一种简写形式,将相关数据成员的初始化列表写在函数名括号后,从而可以省略函数体中的相应数据成员赋值语句。

Human::Human(string humansName, int humansAge) : name(humansName), age(humansAge)
{
}

上面这种写法和下面这种写法具有同样的效果:

Human::Human(string humansName, int humansAge)
{name = humansName; age = humansAge;
}

2.6 复制构造函数

2.6.1 浅复制及其问题

复制一个类的对象时,只复制其指针成员但不复制指针指向的缓冲区,其结果是两个对象指向同一块动态分配的内存。销毁其中一个对象时,delete[] 释放这个内存块,导致另一个对象存储的指针拷贝无效。这种复制被称为浅复制。

如下为浅复制的一个示例程序:

#include <iostream>
#include <string.h>
using namespace std;class MyString
{
private:char* buffer;public:MyString(const char* initString){buffer = NULL;if(initString != NULL){buffer = new char [strlen(initString) + 1];strcpy(buffer, initString);}}~MyString(){cout << "Invoking destructor, clearing up" << endl;delete [] buffer;}int GetLength() { return strlen(buffer); }const char* GetString() { return buffer; }
};void UseMyString(MyString str)
{cout << "String buffer in MyString is " << str.GetLength();cout << " characters long" << endl;cout << "buffer contains: " << str.GetString() << endl;return;
}int main()
{MyString sayHello("Hello from String Class");UseMyString(sayHello);return 0;
}

分析一下 UseMyString(sayHello); 这一语句:

  1. 执行对象浅复制,将实参 sayHello 复制给形参 str,复制了数据成员(指针)的值,但未复制成员指向的缓冲区。因此两份对象拷贝的指针数据成员(char *buffer)指向同一内存区。
  2. UseMyString() 返回时,str 析构,内存区被回收
  3. main() 返回时,sayHello 析构,再次回收内存区,导致段错误

2.6.2 复制构造函数:确保深复制

复制构造函数是一个重载的构造函数,由编写类的程序员提供。每当对象被复制时,编译器都将调用复制构造函数。

复制构造函数函数语法如下:

class MyString
{MyString(const MyString& copySource); // copy constructor
};MyString::MyString(const MyString& copySource)
{// Copy constructor implementation code
}

复制构造函数接受一个以引用方式传入的当前类的对象作为参数。这个参数是源对象的别名,您使用它来编写自定义的复制代码,确保对所有缓冲区进行深复制。

复制构造函数的参数必须按引用传递,否则复制构造函数将不断调用自己,直到耗尽系统的内存为止。原因就是每当对象被复制时,编译器都将调用复制构造函数,如果参数不是引用,实参不断复制给形参,将生成不断复制不断调用复制构造函数。

示例程序如下:

#include <iostream>
#include <string.h>
using namespace std;class MyString
{
private:char* buffer;public:MyString() {}MyString(const char* initString) // constructor{buffer = NULL;cout << "Default constructor: creating new MyString" << endl;if(initString != NULL){buffer = new char [strlen(initString) + 1];strcpy(buffer, initString);cout << "buffer points to: 0x" << hex;cout << (unsigned int*)buffer << endl;}}MyString(const MyString& copySource) // Copy constructor{buffer = NULL;cout << "Copy constructor: copying from MyString" << endl;if(copySource.buffer != NULL){// allocate own buffer buffer = new char [strlen(copySource.buffer) + 1];// deep copy from the source into local bufferstrcpy(buffer, copySource.buffer);cout << "buffer points to: 0x" << hex;cout << (unsigned int*)buffer << endl;}}// Destructor~MyString(){cout << "Invoking destructor, clearing up" << endl;delete [] buffer;}int GetLength() { return strlen(buffer); }const char* GetString(){ return buffer; }
};void UseMyString(MyString str)
{cout << "String buffer in MyString is " << str.GetLength();cout << " characters long" << endl;cout << "buffer contains: " << str.GetString() << endl;return;
}int main()
{MyString sayHello("Hello from String Class");UseMyString(sayHello);return 0;
}

再看 UseMyString(sayHello); 这一语句:

  1. 每当对象被复制时,编译器都将调用复制构造函数。将实参复制给形参时,编译器就会调用复制构造函数。
  2. 所以这里的 str 是通过调用复制构造函数进行的初始化,对实参进行了深复制。形参与实参中的指针成员各指向自己的缓冲区。
  3. 所以析构是正常的,示例程序运行没有问题。

同样,如果没有提供复制赋值运算符 operator=,编译器提供的默认复制赋值运算符将导致浅复制。

关于复制构造函数的注意事项如下:

  1. 类包含原始指针成员(char *等)时,务必编写复制构造函数和复制赋值运算符。
  2. 编写复制构造函数时,务必将接受源对象的参数声明为 const 引用。
  3. 声明构造函数时务必考虑使用关键字 explicit,以避免隐式转换。
  4. 务必将类成员声明为 std::string 和智能指针类(而不是原始指针),因为它们实现了复制构造函数,可减少您的工作量。除非万不得已,不要类成员声明为原始指针。

2.6.3 移动构造函数:改善性能

class MyString
{// 代码同上一示例程序,此处略
};MyString Copy(MyString& source)
{MyString copyForReturn(source.GetString()); // create copyreturn copyForReturn;                       // 1. 将返回值复制给调用者,首次调用复制构造函数
}int main()
{MyString sayHello ("Hello World of C++");MyString sayHelloAgain(Copy(sayHello));     // 2. 将 Copy() 返回值作实参,再次调用复制构造函数return 0;
}

上例中,参考注释,实例化 sayHelloAgain 对象时,复制构造函数被调用了两次。如果对象很大,两次复制造成的性能影响不容忽视。

为避免这种性能瓶颈, C++11 引入了移动构造函数。移动构造函数的语法如下:

// move constructor
MyString(MyString&& moveSource)
{if(moveSource.buffer != NULL){buffer = moveSource.buffer;     // take ownership i.e. 'move'moveSource.buffer = NULL;       // set the move source to NULL}
}

有移动构造函数时,编译器将自动使用它来“移动”临时资源,从而避免深复制。增加移动构造函数后,上一示例中,将首先调用移动构造函数,然后调用复制构造函数,复制构造函数只被会调用一次。

3. 析构函数

析构函数在对象销毁时被调用。执行去初始化操作。

  1. 析构函数只能有一个,不能被重载。
  2. 若用户未提供析构函数,编译器会生成一个伪析构函数,但是这个伪析构函数是空的,不会释放堆内存。

每当对象不再在作用域内或通过 delete 被删除进而被销毁时,都将调用析构函数。这使得析构函数成为重置变量以及释放动态分配的内存和其他资源的理想场所。

4. 构造函数与析构函数的其他用途

4.1 不允许复制的类

假设要模拟国家政体,一个国家只能一位总统,President 类的对象不允许复制。

要禁止类对象被复制,可将复制构造函数声明为私有的。为禁止赋值,可将赋值运算符声明为私有的。复制构造函数和赋值运算符声明为私有的即可,不需要实现。这样,如果代码中有对对象的复制或赋值,将无法编译通过。形式如下:

class President
{
private:President(const President&);              // private copy constructorPresident& operator= (const President&);  // private copy assignment operator// … other attributes
};

4.2 只能有一个实例的单例类

前面讨论的 President 不能复制,不能赋值,但存在一个缺陷:无法禁止通过实例化多个对象来创建多名总统:

President One, Two, Three;

要确保一个类不能有多个实例,也就是单例的概念。实现单例,要使用私有构造函数、私有赋值运算符和静态实例成员。

将关键字 static 用于类的数据成员时,该数据成员将在所有实例之间共享。
将关键字 static 用于成员函数(方法)时,该方法将在所有成员之间共享。
将 static 用于函数中声明的局部变量时,该变量的值将在两次调用之间保持不变。

4.3 禁止在栈中实例化的类

将析构函数声明为私有的。略

4.4 使用构造函数进行类型转换

5. this 指针

在类中,关键字 this 包含当前对象的地址,换句话说, 其值为&object。在类成员方法中调用其他成员方法时, 编译器将隐式地传递 this 指针。

调用静态方法时,不会隐式地传递 this 指针,因为静态函数不与类实例相关联,而由所有实例共享。要在静态函数中使用实例变量,应显式地声明一个形参,并将实参设置为 this 指针。

6. sizeof 用于类

sizeof 用于类时,值为类声明中所有数据属性占用的总内存量,单位为字节。是否考虑对齐,与编译器有关。

7. 结构与类的不同之处

结构 struct 与类 class 非常相似,差别在于程序员未指定时,默认的访问限定符(public 和 private)不同。因此,除非指定了,否则结构中的成员默认为公有的(而类成员默认为私有的);另外,除非指定了,否则结构以公有方式继承基结构(而类为私有继承)。

转载于:https://www.cnblogs.com/leisure_chn/p/11081537.html

http://www.lbrq.cn/news/2383489.html

相关文章:

  • 建外贸网站用什么主机百度seo效果
  • 手机网站怎么做微信登陆seo诊断专家
  • 国内优秀app界面设计案例专业seo公司
  • 做网站建设公司赚钱网络推广渠道都有哪些
  • 珠海专业网站制作百度一下官网
  • 外贸网站域名能用cn做后缀吗免费制作链接
  • 做好的网站百度推广客服电话24小时
  • 重庆网站建设cqhtwl百度搜索排名优化
  • 北京哪家做网站seo怎么弄
  • 做网上任务赚钱的网站市场seo是什么
  • 泰国如何做网站推广万网官网首页
  • 网络搭建与维护是什么广州百度网站排名优化
  • 网站备案 暂住证企业营销案例
  • 做知识产权相关的网站百度推广账号登陆入口
  • 湘潭做网站推荐磐石网络网络优化的流程
  • 专业做公墓 陵园的网站优化落实疫情防控新十条
  • 推荐企业门户网站建设2022近期时事热点素材摘抄
  • wordpress主题集成插件下载seo优化点击软件
  • 网站模块设计怎么做怎样打开网站
  • 重庆专业做网站seo搜索引擎优化价格
  • 建设政府网站多少钱百度搜索趋势
  • 企业做定制网站的好处宣传推广方式有哪些
  • 西宁做网站公司排名深圳推广公司推荐
  • 海淀深圳网站建设公司成人大学报名官网入口
  • 保定网站建设优化百度代理查询
  • 网站公安部备案号小广告怎么能弄干净
  • 做彩票网站是违法的吗青岛seo关键词优化排名
  • 网站建设水平如何评价现在感染症状有哪些
  • 山东网站开发制作市场营销手段有哪四种
  • wordpress admin主题宁波seo专员
  • b-up:Enzo_Mi:深度学习基础知识
  • 习题4.1 输出3个人的顺序
  • 西门子工业软件全球高级副总裁兼大中华区董事总经理梁乃明先生一行到访庭田科技
  • JavaScript中的Window对象
  • arping(ARP协议网络测试工具)
  • 题解:CF1829H Don‘t Blame Me