我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C++primer类的基础精讲

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C++primer类的基础精讲

定义抽象数据类型

初探this和

struct Sales_data
{
    string isbn(){return bookNo;}
    Sales_data & combine(const Sales_data&);
    double avg_price() const;
    string bookNo;
    unsigned units_sold=0;
    double revenue=0;
};
Sales_data total;

引入this

对于isbn成员函数的调用: total.isbn();

当我们调用成员函数时,实则上是在替某个对象调用它。在上面的调用中,当isbn返回bookNo时,实际上隐式地返回total.bookNo.

成员函数通过一个名为this的额外隐式参数来访问调用它的那个对象。当我们调用一个成员函数时,用请求该函数的对象地址初始化this。例如,如果调用total.isbn(),编译器负责把total的地址传递给isbn的隐式形参this,可以等价认为编译器将该调用重写成Sales_data::isbn(&total),调用Sales_data时的isbn成员时传入了total的地址。

在成员函数内部,我们可以直接使用调用该函数的对象的成员,而无须通过成员访问运算符来做到这一点,因为this所指的正是这个对象。任何对类成员的直接访问都被看做this的隐式调用,例如,isbn在使用bookNo时,隐式地使用this指向的成员,就如同this->bookNo一样。

构造函数

定义:类通过一个或几个特殊的成员函数来控制其对象的初始化,这些函数叫做构造函数。

无论何时,只要类的对象被创建,就会执行构造函数。

构造函数的名字和类名一样,构造函数没有返回类型,一个类可以拥有多个构造函数,但每个构造函数之间必须在参数数量或参数类型上存在不同。且构造函数不能被声明成const。

当一个类没有定义任何构造函数时,编译器会给类自动添加一个默认构造函数,该构造函数无须任何实参对对象进行初始化。

对前面的Sales_data类进行编写构造函数

struct Sales_data
{
    Sales_data()=default;
    Sales_data(const string &s):bookNo(s)()
    Sales_data(const string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}
    Sales_data(istream &)
    string isbn() const{return bookNo;}
    Sales_data &combine(const Sales_data&);
    double avg_price() const;
    string bookNo;
    unsigned units_sold=0;
    double revenue=0.0;
}

(1)=default的含义

如果需要默认构造函数起作用,那么可以在参数列表后面写上=default来要求编译器生成默认构造函数。

(2)构造函数初始值列表

Sales_data(const string &s):bookNo(s)()
Sales_data(const string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}

上面出现了两个新的构造函数的写法,该部分称为构造函数初始值列表。

负责为新创建的对象的一个或几个数据成员赋初值。构造函数初始值是成员名字的一个列表,每个名字后面紧跟括号括起来的成员初始值。

当某个数据成员被构造函数初始值列表忽略时,他将以合成默认构造函数相同的方式隐式初始化。所以,第一个构造函数等价于:

Sales_data(const string &s):bookNo(s),units_sold(0),revenue(0)();

访问控制和封装

访问控制符public和private

定义在public说明符之后的成员在整个程序可被访问。

定义在private说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问。

Sales_data类的新形式

class Sales_data
{
public:
    Sales_data()=default;
    Sales_data(const string &s):bookNo(s)()
    Sales_data(const string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}
    Sales_data(istream &)
    string isbn() const{return bookNo;}
    Sales_data &combine(const Sales_data&);
private:
    double avg_price() const;
    string bookNo;
    unsigned units_sold=0;
    double revenue=0.0;
}

友元

类允许其他类或者函数访问他的非公有成员,方法是令其他类或者函数成为他的友元。如果一个类想把一个函数作为他的友元,只需要增加一个friend关键字开始的函数声明语句即可

class Sales_data
{
    friend Sales_data add(const Sales_data &,const Sales_data&);
    friend istream &read(istream&,Sales_data&);
    friend ostream &print(ostream&,const Sales_data&)
public:
    Sales_data()=default;
    Sales_data(const string &s):bookNo(s)()
    Sales_data(const string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}
    Sales_data(istream &)
    string isbn() const{return bookNo;}
    Sales_data &combine(const Sales_data&);
private:
    double avg_price() const;
    string bookNo;
    unsigned units_sold=0;
    double revenue=0.0;
}

友元的声明只能出现在类定义的内部。友元不是类的成员,也不受他所在区域访问控制级别的约束。

类的其他特性

可变数据成员

在一个const成员函数中,若希望修改类的某个数据成员,可以通过在变量的声明中加入mutable关键字实现

class screen{
public:
        void some_menmber() const;
private:
        mutable size_t access_ctr
};
void screen::some_member() const
{
    ++access_ctr
}

返回*this的成员函数

inline Screen &Screen::set(char c)
{
    contents[cursor]=c;
    return *this;
}
inline Screen &Screen::set(pos r,pos col,char ch)
{
    contents[r*width+col]=ch;
    return *this;
}
inline Screen &Screen::move(pos r,pos c)
{
    pos row=r*width;
    cursor=row+c;
    return *this;
}

move和set一样,返回的值是对对象的引用。

myScreen.move(4,0).set('#');

等同于

myScreen.move(4.0);

myScreen.set('#');

假如我们定义的返回类型不是引用,则move的返回值将是*this的副本,因此调用set只能改变临时副本,不能改变myScreen的值

友元类

例如,window_mgr类的某些成员需要访问screen类的内部数据,例如window_mgr的clear函数将一个指定的screen类的内容设置为空白。

class Screen{
//window_mgr的成员可以访问Screen类的私有部分
friend class Window_mgr
//Screen类剩余部分
}
class Window_mgr{
public:
    using ScreenIndex=std::vector<Screen>::size_type
    void clear(ScreenIndex);
private:
    std::vector<Screen> screens{Screen(24,80,' ')}
};
void Window_mgr::clear(ScreenIndex)
{
    Screen &s=screen[i];
    s.contens=string(s.height*swidth,' ')
}

构造函数再探

构造函数初始值列表

(1)构造函数的初始值有时必不可少

如果成员是const或者是引用的话,必须将其初始化

class ConstRef
{
public:
    ConstRef(int ii);
private:
    int i;
    const int ci;
    int &ri;
};

成员ci和ri必须被初始化,如果没有为他们提供构造函数初始值的话将引发错误。正确形式应该是: ConstRef::ConstRef(int ii):i(ii),ci(ii),ri(i){};

如果成员是const,引用,或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些成员提供初值。

(2)成员初始化顺序

成员初始化的顺序与他们在类定义中的出现顺序一致。一般来说初始化的顺序没什么特别要求,不过如果一个成员是用另一个成员来初始化的,那么着两个成员的初始化顺序就关键了。

例如

class X
{
    int i;
    int j;
public:
    X(int val):j(val),i(j){}
};

而编译器实际上是先初始化i,在初始化j,而初始化i的时候发现j没有值,所以上述构造函数会发生错误。

默认构造函数的作用

当对象被默认初始化或值初始化时自动执行默认构造函数。

默认初始化在以下情况下发生:

(1)当我们在块作用域内不适用任何初始值定义一个非静态变量或数组时。

(2)当一个类本身含有类类型的成员且使用合成的默认构造函数时

(3)当类类型的成员没有在构造函数初始值列表中显示地初始化时

值初始化在以下情况发生:

(1)在数组初始化的过程中如果我们提供的初始值数量少于数组的大小时

(2)当我们不适用初始值定义一个局部静态变量

使用默认构造函数

下面的obj的声明可以正常通过

Sales_data obj();//正确,定义了一个函数而非对象
if(obj.isbn()==primer_5th_ed.isbn())//错误:obj是一个函数

但当我们试图使用obj时,编译器将报错,提示我们不能使对函数使用成员访问运算符。因为obj的实际含义是一个不接受任何参数的函数并且其返回值是Sales_data类型的对象。

如果想定义一个使用默认构造函数进行初始化的对象,正确方法是去掉对象名之后的空括号对。

Sales_data obj;

聚合类

满足一下条件的类是聚合类:

(1)所有成员都是public的

(2)没有定义任何构造函数

(3)没有类内初始值

(4)没有基类,也没有虚函数

例:

struct Data
{
    int val;
    string s;
};

类的静态成员

class Account
{
public:
    void calculate(){amount+=amount*interestRate;}
    static double rate(){return interestRate;}
    static void rate(double);
private:
    string owner;
    double amount;
    static double interestRate;
    static double initRate();
}

类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据,因此,每个Account对象将包含两个数据成员:owner和amout。只存在一个interestRate对象而且他被所有account对象共享。

静态成员函数也不与任何对象绑定在一个,他们不包含this指针。作为结果,静态成员函数不能声明成const的,而且我们也不能在static函数体内使用this指针。

到此这篇关于C++ primer类的基础精讲的文章就介绍到这了,更多相关C++类内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C++primer类的基础精讲

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C#枚举类型的基础讲解

本篇内容主要讲解“C#枚举类型的基础讲解”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#枚举类型的基础讲解”吧!对于C#枚举类型不仅可以提高程序的可读性,而且可以减少因底层值发生改变而导致的程
2023-06-18

Jetpack Compose入门基础全面精讲

开始布局部分。这部分我个人感觉没有必要每个组件、属性都详细说到,否则篇幅会很长。建立起Compose中的组件与 Android Views的一个对应关系就够了。具体还是需要在实际的使用中去熟悉
2022-11-13

JavaArrayList类的基础使用讲解

数组的长度是固定的,无法适应数据变化的需求。为了解决这个问题,Java提供了另一个容器java.util.ArrayList集合类,让我们可以更便捷的存储和操作对象数据。本文就将通过示例聊聊ArrayList类的基础使用,感兴趣的可以了解一下
2022-11-13

怎样讲述C++中的C++基类

这篇文章给大家介绍怎样讲述C++中的C++基类,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。C++语言中有一个很重要的特性:Private派生确保C++基类中的方法只能被派生类的对象的方法间接使用,而不能被外部使用,除
2023-06-17

C++类模板与函数模板基础详细讲解

C++语言的模板技术包括函数模板和类模板,模板技术是一种代码重用技术,函数和类是C++语言中两种主要的重用代码形式,这篇文章主要介绍了C++函数模板和类模板,需要的朋友可以参考下
2022-11-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录