广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++primer类的基础精讲
  • 817
分享到

C++primer类的基础精讲

2024-04-02 19:04:59 817人浏览 安东尼
摘要

目录定义抽象数据类型初探this和构造函数访问控制和封装友元类的其他特性可变数据成员返回*this的成员函数友元类构造函数再探构造函数初始值列表默认构造函数的作用聚合类类的静态成员定

定义抽象数据类型

初探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++类内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++primer类的基础精讲

本文链接: https://www.lsjlt.com/news/153159.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

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

下载Word文档
猜你喜欢
  • C++primer类的基础精讲
    目录定义抽象数据类型初探this和构造函数访问控制和封装友元类的其他特性可变数据成员返回*this的成员函数友元类构造函数再探构造函数初始值列表默认构造函数的作用聚合类类的静态成员定...
    99+
    2022-11-13
  • C#枚举类型的基础讲解
    本篇内容主要讲解“C#枚举类型的基础讲解”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#枚举类型的基础讲解”吧!对于C#枚举类型不仅可以提高程序的可读性,而且可以减少因底层值发生改变而导致的程...
    99+
    2023-06-18
  • Java基础精讲方法的使用
    目录一、方法二、方法的重载三、方法递归四、小结一、方法 方法是什么? 在Java中方法就相当于C语言中的函数。因为有时候我们需要一块代码重复使用,这时候就可以使用方法。 为什么要用方...
    99+
    2022-11-13
  • C++ Primer的变量和基本类型详解
    目录1.类型转换含有无符号类型的表达式2.字面值常量整形和浮点型字面值字符和字符串字面值转移序列指定字面值的类型布尔字面值和指针字面值总结1.类型转换 对象的类型定义了对象能包含的数...
    99+
    2022-11-12
  • c++primer:变量和基本类型详解
    目录前言类型转换变量声明与定义的关系变量命名规范复合类型引用指针const限定符const的引用指针和constconstexpr和常量表达式auto类型说明符decltype头文件...
    99+
    2022-11-12
  • Jetpack Compose入门基础全面精讲
    目录1. Column2. Row3. Box4. BoxWithConstraints5. ConstraintLayout6. 参考1. Column 子元素按竖直顺序排列,相当...
    99+
    2022-11-13
    Jetpack Compose入门 Jetpack Compose
  • C++基础概念讲述
    目录1.C++相关网站推荐2.C++和C的关系3.C++特性说明3.1与底层硬件紧密结合3.2对象生命周期的精确控制3.3Zero-Overhead Abstraction首先,通过...
    99+
    2022-11-12
  • SpringBoot2零基础到精通之数据库专项精讲
    目录1 数据库连接1.1 配置数据库连接信息1.2 整合Druid数据源2 SpringBoot整合MyBatis2.1 配置文件开发2.2 纯注解开发3 SpringBoot整合M...
    99+
    2022-11-13
  • JavaArrayList类的基础使用讲解
    目录什么是ArrayList类ArrayList使用步骤常用方法和遍历如何存储基本数据类型数组的长度是固定的,无法适应数据变化的需求。为了解决这个问题,Java提供了另一个容器 ja...
    99+
    2022-11-13
    Java ArrayList类使用 Java ArrayList类
  • 【Java 基础】Java 数组、方法极致精讲
    《Java 零基础入门到精通》专栏持续更新中。通过本专栏你将学习到 Java 从入门到进阶再到实战的全套完整内容,所有内容均将集中于此专栏。无论是初学者还是有经验的开发人员,都可从本专栏获益。 ...
    99+
    2023-09-09
    java jvm 开发语言 后端 算法
  • 怎样讲述C++中的C++基类
    这篇文章给大家介绍怎样讲述C++中的C++基类,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。C++语言中有一个很重要的特性:Private派生确保C++基类中的方法只能被派生类的对象的方法间接使用,而不能被外部使用,除...
    99+
    2023-06-17
  • c# 异步编程基础讲解
    目录Task 和 Task<T>I/O 受限异步操作CPU 受限异步操作异步编程模式现代应用程序广泛使用文件和网络 I/O。I/O 相关 API 传统上默认是阻塞的,导致...
    99+
    2022-11-12
  • C++类模板与函数模板基础详细讲解
    目录函数模板类模板总结函数模板 当我们想要定义一个可以支持泛型的函数时,就要采用函数模板的方式了。所谓泛型就是可以支持多种类型的操作,比如我们定义一个compare操作,他可以根据传...
    99+
    2022-11-13
    C++类模板 C++函数模板
  • C++抽象基类讲解
     公众号:Coder梁(ID:Coder_LT) 这一篇文章来聊聊抽象基类(abstract base class简称ABC)。 我们之前说过,在我们实现继承的时候,需要保...
    99+
    2022-11-12
  • C#表达式树Expression基础讲解
    什么是表达式树 表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的二元运算等。可以对表达式树中的代码进行编辑和运算。 这样能够动态...
    99+
    2022-11-12
  • c语言 指针零基础讲解
    1.指针是什么(可能有点难理解) 指针的是啥? 指针实际上就是地址,地址就是系统给定的编号,编号就是一个个内存单元。 在某种情况来说指针=地址=编号=内存单元。 指针就是地址,顾名思...
    99+
    2022-11-13
  • C++入门之模板基础讲解
    目录前言引入模板函数模板模板的匹配原则模板的显示调用类模板注意1注意2总结 前言 今天博主将要介绍的内容是–模板,他在C++中具有非常重要的位置.至于什么是模板呢?我们请看...
    99+
    2022-11-12
  • Java类与对象超基础讲解
    目录什么是面向对象面向过程与面向对象类与对象的使用类与对象的使用与说明对象的初始化this的使用构造方法this可以调用本类的构造方法什么是面向对象 Java语言是一个纯面向对象的语...
    99+
    2022-11-13
  • Java基础全面讲解StringBuffer类的使用
    目录StringBuffer类常用方法字符串连接指定位置添加内容字符串反转替换指定范围的内容字符串截取删除指定范围的字符串查找指定的内容是否存在String与StringBuffer...
    99+
    2022-11-13
  • C语言零基础精通变量与常量
    目录1.变量和常量的概念2.变量的类型3.变量的分类4.变量的使用5.变量的作用域和生命周期6.常量的分类1.变量和常量的概念 生活中的一些数据有些数据不能变:血型、性别、圆周率。有...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作