前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++系列笔记(三)

C++系列笔记(三)

作者头像
墨明棋妙27
发布2022-08-24 15:22:46
2130
发布2022-08-24 15:22:46
举报
文章被收录于专栏:1996

导读】《21天学通C++》这本书通过大量精小短悍的程序详细而全面的阐述了C++的基本概念和技术,包括管理输入/输出、循环和数组、面向对象编程、模板、使用标准模板库以及创建C++应用程序等。这些内容被组织成结构合理、联系紧密的章节,每章都可在1小时内阅读完毕,都提供了示例程序清单,并辅以示例输出和代码分析,以阐述该章介绍的主题。 本文是系列笔记的第三篇,主要讲的是类、对象、析构函数等知识,欢迎各位阅读指正!

1、类和对象 声明类使用关键字class,并在他后面依次包含类名、一组放在{ }内的成员属性和方法以及结尾的分号。

代码语言:javascript
复制
class Human
{
    //Data attributes:
    string Name;
    string Gender;
    //Methods:
    void Talk(string TextToTalk);
    void IntroduceYouself( );
    ……
} ;

就像int分配动态内存一样,也可以使用new为Human对象动态的分配内存;

代码语言:javascript
复制
Human* pAnotherHuman = new Human();  //动态的分配内存
delete pAnotherHuman;

使用句点运算符来访问成员

代码语言:javascript
复制
Human Tom;
Tom.DateBirth="1970";

使用指针运算符(->)访问成员 如果对象是使用new在自有储存区中实例化的,或者有指向对象的指针,则可以使用指针运算符(->)来访问成员属性和方法。

代码语言:javascript
复制
Human* pTom=new Human();
pTom->DataOfBirth="1970";
pTom->IntroduceYouself();
delete pTom;

下面结合代码来看一下:

代码语言:javascript
复制
#include<iostream>
#include<string>
using namespace std;
        class Human
        {
        private:
               string Name;
               int Age;
        public:
               void SetName(string HumansName)
               {
                       Name = HumansName;
               }
               void SetAge(int HumansAge)
               {
                       Age = HumansAge;
               }
               void IntroduceSelf()
               {
                       cout << "I am" + Name << "and am";
                       cout << Age << "years old" << endl;
               }
        };
        int main()
        {
               Human FirstMan;
               FirstMan.SetName("Adam");
               FirstMan.SetAge(30);
               FirstMan.IntroduceSelf();
        }

2、构造函数

构造函数是一种特殊的函数,它与类同名且不返回任何值。因此,Human类在声明内的构造函数声明类似于下面:

代码语言:javascript
复制
class Human
{
 public:
    Human( )
    {
          //代码
    }
};

在类声明外定义构造函数的代码如下:

代码语言:javascript
复制
class Human
{
public:
    Human( );
 };
 Human :: Human()
 {
    //代码
 }

::被称为作用域解析运算符。例如:Human::DateOfBirth指的是在Human类中声明的变量DateOfBirth,而::DateOfBirth表示全局作用域中的变量DateOfBirth。包含初始化列表的构造函数的代码如下:

代码语言:javascript
复制
class Human
{
public:
  Human(string InputName = "Adam" , int Age = 25 )
            : Name(InputName) , Age(InputAge)
  {
        //代码
  }
};

初始化列表由包含在括号当中的参数声明后面的冒号标识,冒号后面列出了各个成员变量及其初始化值。初始化值可以是参数,也可以是固定的值。 3、析构函数

析构函数在对象销毁时自动被调用。析构函数看起来也像一个与类同名的函数,但前面有一个波浪号(~)。因此,Human类的析构函数声明类似于下面这样,这是在类里面声明:

代码语言:javascript
复制
class Human
{
public:
    ~Human( )
    {
        // code here
    }
};

在类声明外定义析构函数:

代码语言:javascript
复制
class Human
{
public:
    ~Human();
};
Human::~Human()
{
    //code here
}

析构函数与构造函数的作用完全相反。析构函数是重置变量以及释放动态分配的内存和其他资源的理想场所。析构函数典型代码如下:

代码语言:javascript
复制
#include<iostream>
#include<string>
using namespace std;
class MyString
{
private:
        char* Buffer;
public:
        MyString(const char* InitialInput)
        {
               if (InitialInput != NULL)
               {
                       Buffer = new char[strlen(InitialInput + 1)];
                       strcpy(Buffer, InitialInput);
               }
               else
                       Buffer = NULL;
        }
        ~MyString()
        {
               cout << "Invoking destructor,cleaning up" << endl;
               if (Buffer != NULL)
                       delete[] Buffer;
        }
        int GetLength()
        {
               return strlen(Buffer);
        }
        const char* GetString()
        {
               return Buffer;
        }
};
int main()
{
        MyString SayHello("Hello from string class:");
        cout << "string buffer in MyString is:" << SayHello.GetLength();
        cout << "characters long" << endl;
        cout << "Buffer contains:";
        cout << "Buffer contains:" << SayHello.GetString();
}

程序运行输出为:

代码语言:javascript
复制
string buffer in MyString is:24characters long
Buffer contains:Buffer contains:Hello from string class:Invoking destructor,cleaning up

析构函数不能重载,每个类都只能有一个析构函数。如果你忘记实现一个析构函数,编译器将创造一个伪(dummy)析构函数并调用他。伪析构函数为空,既不释放动态分配的内存。 复制构造函数

浅复制:复制类对象时,将复制其指针成员,都不复制指针指向的缓冲区,造成两个对象指向同一块动态分配的内存,会威胁程序的稳定性。深复制:所以要将浅复制的参数复制变成地址传递,即按参数引用传递而不是进行二进制复制。代码示例如下

代码语言:javascript
复制
#include<iostream>
#include<string>
using namespace std;
class MyString
{
private:
        char* Buffer;
public:
        MyString(const char* InitialInput)
        {
               cout << "Constructor:creating new String" << endl;
               if (InitialInput != NULL)
               {
                       Buffer = new char[strlen(InitialInput + 1)];
                       strcpy(Buffer, InitialInput);
                       cout << "Buffer points to:0x" << hex;
                       cout << (unsigned int*)Buffer << endl;
               }
               else
                       Buffer = NULL;
        }
        //复制构造函数
        MyString(const MyString& CopySource)
        {
               cout << "copy constructeor:copy from MyString" << endl;
               f (CopySource.Buffer != NULL)
               {
                       Buffer = new char[strlen(CopySource.Buffer) + 1];
                       strcpy(Buffer, CopySource.Buffer);
                       cout << "Buffer points to:0x" << hex;
                       cout << (unsigned int*)Buffer << endl;
               }
               else
                       Buffer = NULL;
        }
        ~MyString()
        {
               cout << "Invoking destructor,cleaning up" << endl;
               if (Buffer != NULL)
                       delete[] Buffer;
        }
        int GetLength()
        {
               return strlen(Buffer);
        }
        const char* GetString()
        {
               return Buffer;
        }
};
void UseMyString(MyString Input)
{
        cout << "Sting Buffer in mystring is" << Input.GetLength();
        cout << "characters long" << endl;
        cout << "Buffer contains:" << Input.GetString() << endl;
        return;
}
int main()
{
        MyString SayHello("Hello from string class:");
        UseMyString(SayHello);
}

程序运行输出:

代码语言:javascript
复制
Constructor:creating new String
Buffer points to:0x004BD5A0
copy constructeor:copy from MyString
Buffer points to:0x004BD5E8
Sting Buffer in mystring is18characters long
Buffer contains:Hello from string class:
Invoking destructor,cleaning up
Invoking destructor,cleaning up

MyString包含原始指针成员char* Buffer,一般不要为类成员声明原始指针,而应该使用std::string。在没有原始指针的情况下,都不需要编写复制构造函数,这是因为编译器添加的默认复制构造函数将调用成员对象(如:std::string)的复制构造函数。

今天的内容就到这里,我们下次再见啦!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 计算机视觉CV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
腾讯云代码分析
腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档