类的定义

  简单的来说类就是数据和它的操作的一种封装,内部提供接口函数

  类的成员函数的声明必须在类的内部,而它的定义则既可以放在类的内部也可以放在类的外部。(一般在类内进行声明,类外实现函数定义)

  定义在类内部的函数是隐式的inline函数(内联函数)。

构造函数

  功能:初始化类对象的数据成员。无论何时只要类的对象被创建,就会执行构造函数。

  特点:构造函数的名字和类的名字相同。类可以包含有多个构造函数(类似重载函数)。不同于其他成员函数,构造函数不能被声明为const,且没有返回类型。

  默认构造函数:无需任何实参,执行默认初始化。

  合成默认构造函数:只有当类没有声明任何构造函数时,编译器才会自动隐式地定义一个默认构造函数。

class Sales_data
{
public:
Sales_data() = default;
Sales_data(std::string s):bookNo(s), units_sold(), revenue(0.0) { }
Sales_data(std::string s, unsigned n, double p): bookNo(s), units_sold(n), revenue(p) { }
private:
std::string bookNo ; //编号
unsigned units_sold = ; //销售数量
double revenue = ; //总销售额
}; int main()
{
Sales_data item1;
Sales_data item2("wangweihao");
Sales_data item3("wangweihao", , ); print(cout, item1) << endl;
print(cout, item2) << endl;
print(cout, item3) << endl;
return ;
}

  情况1  去掉 Sales_data( ) = default;

  报错:没有定义默认构造函数,当我们自己定义了其他任何一种构造函数时,编译器就不会帮我们合成默认构造函数。这时需要加上Sales_data( ) = default;  定义默认构造函数。

  函数成员初始化的顺序:与它们在类定义中的出现顺序一致。tips:最好令构造函数初始值顺序与成员声明的顺序保持一致,尽可能避免使用某些成员初始化其他成员,而是使用传入的变量。

举例:

 class X{
int i;
int j;
public: // 错误:未定义的,i在j之前被初始化
X(int val):j(val),i(j){}
};

类内定义构造函数:

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

先执行初始值列表 bookNo(s), units_sold(n), revenue(n * p)  , 再执行{} 内函数体的内容。

委托构造函数(C++11)

  一个委托构造函数使用它所属类的其他构造函数来执行它的初始化过程。加入被委托的构造函数函数体有代码的话,先执行完代码,再执行委托者的函数体。

class Sales_data {

public:
Sales_data(const std::string& s, unsigned n, double p)
: bookNo(s), units_sold(n), revenue(n * p){}
// 其余构造函数全都委托给另一个构造函数
Sales_data() : Sales_data("", , 0.0f){}
Sales_data(const std::string& s) : Sales_data(s, , 0.0f){}
Sales_data(std::istream &is): Sales_data() {read(is,*this};}
}

构造函数在数组中的使用

                

  指针如果没有指向确定值,就没有生成对应的对象,也就没有调用构造函数。

  

  new返回的是地址,所以前两个有生成对应的对象,而pArray2这个元素生成并不会导致任何对象的生成,所以这条语句, 只是生成了2个对象.

引入this

  • 成员函数通过一个名为this的额外的隐式参数来访问调用它的那个对象。
  • 任何对类成员的访问都被看作this的隐式引用。this是一个常量指针,不允许改变this中保存的地址

  const 常量成员函数:C++允许把const关键字写在函数的参数列表后面,表示this是一个指向常量对象的指针。一个const成员函数如果以引用的形式返回*this,那么它的返回类型将是常量引用。

访问与封装

  • 定义在public说明符之后的成员在整个程序内可被访问,public成员定义类的接口。
  • 定义在private说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问。(隐藏了类的实现细节)

友元

  类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数称为它的友元(friend)。如果想把一个函数作为友元,只需要添加一条以friend关键字开头的函数声明即可。

  • 重载函数作为友元,尽管名字相同,但是他们依然是不同的函数。要分别对每一个函数进行声明

  • 就算在内部定义友元函数,我们也应该在外部声明它使得它可见。

    class Sales_data {
    friend std::istream& read(std::istream& is, Sales_data& item);
    friend std::ostream& print(std::ostream& os, const Sales_data& item);
    friend Sales_data add(const Sales_data& lhs, const Sales_data& rhs);
    }
  • 当把一个成员函数声明为友元时,我们必须明确指出该成员函数属于哪个类
    class Screen {
    friend void Window_mgr::clear(ScreenIndex);
    }

访问类的成员

  

类的作用域

名字查找

  • 首先,在名字所在的块中寻找其声明语句,只考虑在名字使用之前出现的声明

  • 如果没找到,继续查找外层作用域

  • 如果最终没有找到匹配的报错

类的声明

class Screen;     // Screen 类的声明    

  只声明类而暂时不定义它。称为前向声明,对于类而言,在它声明之后、定义之前是一个不完全类型

应用场景:

  • 定义指向这种类型的指针或引用
  • 声明(但不能定义)以不完全类型作为参数/ 返回类型的函数

Tips:因为只有当类全部完成后类才算被定义,所以一个类的成员不能是该类自己。  然而,一个类的名字出现后,它被认为是声明    过了,因此类允许包含指向自身类型的引用或指针。

ex:定义一对类X和Y,其中X包含一个指向Y的指针,而Y包含一个类型为X的对象。

class Y;
class X{
Y* y = nullptr;
}
class Y{
X x;
}

类的静态成员

  有的时候类需要它的一些成员与类本身直接相关,而不是与类的各个对象保持关联。如:一个银行账户类需要一个数据成员来表示当前的基准利率。

  • 静态成员可以是不完全类型。
  • 一个静态数据成员只能定义一次
  • sizeof 运算符不会计算静态成员变量
  • class CMyclass{
    int n;
    static int s;
    }

    则 sizeof(CMyclass) = 4;

  • 注:在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数。

声明静态成员

  • 静态成员变量在类内声明,且必须带static关键字;在类外初始化,且不能带static关键字
  • 静态成员函数在类内声明,且必须带static关键字;在类外实现,且不能带static关键字
    class Account{
    public:
    void calculate(){amout += amount* interestRate;}
    static double rate(){ return interestRate}
    static void rate(double);
    private:
    std::string owner;
    double amount;
    static double interestRate;
    static double initRate();
    }

使用类的静态成员

  通过作用域运算符::直接访问静态成员

double r;
r = Account::rate();

  

定义静态成员

void Account::rate(double newRate) // 不能带static(重复)
{
interestRate = newRate;
}

  静态成员的类内初始化

  通常情况下,类的静态成员不应该在类内初始化。然而,可以为静态成员提供const整数类型的类内初始值。不过要求静态成员必须是字面值常量类型的constexpr。初始值必须是常量表达式。

ex.找出下面的静态数据成员的声明和定义错误

// exmaple.h
class Example{
public:
static double rate = 6.5; // error: rate should be a constant expression.
static const int vecSize = ;
static vector<double> vec(vecSize);//error: we may not specify an in-class initializer inside parentheses.
};
// example.c
#include "example.h"
double Example::rate;
vector<double> Example::vec;

Fixed:

// example.h
class Example {
public:
static constexpr double rate = 6.5;
static const int vecSize = ;
static vector<double> vec;
}; // example.C
#include "example.h"
constexpr double Example::rate;
vector<double> Example::vec(Example::vecSize);

静态成员实例

  考虑一个需要随时知道矩形总数和总面积的图形处理程序。可以用全局变量来记录总数和总面积,用静态成员将这两个变量封装进类中,就更容易理解和维护。

  

     

C++Primer #7 类的更多相关文章

  1. C++ Primer 与“类”有关的注意事项总结

    C++ 与"类"有关的注意事项总结(一) 1. 除了静态 static 数据成员外,数据成员不能在类体中被显式地初始化. 例如 : class First { int memi = ...

  2. C++Primer学习——类

    我们在创建类的对象时,类不应该仅仅被声明,还应该被定义过,否则无法知道类占用了多少的内存 但是如果一个类的名字已经出现过就被认为是已经声明过了,所以允许包含自己的指针或者引用. 默认构造函数: 当类中 ...

  3. C++ Primer 笔记——类成员指针

    1.当我们初始化一个成员指针或为成员指针赋值时,该指针并没有指向任何数据.成员指针指定了成员而非成员所属的对象,只有当解引用成员指针时,我们才提供对象信息. 2.和普通的函数指针类似,如果成员存在重载 ...

  4. C++ Primer 笔记——类

    1.定义在类内部的函数是隐式的inline函数. 2.因为this的目的总是指向“这个”对象,所以this是一个常量指针,我们不允许改变this中保存的地址. 3.常量成员函数:允许把const关键字 ...

  5. 【C++ Primer 第7章】定义抽象数据类型

    参考资料 1. C++Primer #7 类 Sales_data类 Sales_data.h #include<iostream> #include<string> clas ...

  6. C++类的成员函数的形参列表后面的const

    看到(C++ Primer)类的成员函数这里,突然对成员函数形参列表后面的const感到迷惑. 因为书中开始说是修饰隐含形参this的,然后又说是声明该函数是只读的. 大为不解! 翻资料.找人讨论.. ...

  7. Java类的继承与多态特性-入门笔记

    相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...

  8. 【足迹C++primer】46、动态存储类

    动态存储类 StrVec Class Design StrVec Class Definition class StrVec { public: //构造函数 StrVec():elements(nu ...

  9. C++primer原书中的一个错误(派生类using声明对基类权限的影响)

    在C++primer 第4版的 15章 15.2.5中有以下这样一段提示: "注解:派生类能够恢复继承成员的訪问级别,但不能使訪问级别比基类中原来指定的更严格或者更宽松." 在vs ...

随机推荐

  1. Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 0. 准备工作

    一.关于 Python Python 是全球使用人数增长最快的编程语言!它易于入门.功能强大,从 Web 后端 到 数据分析.人工智能,到处都能看到 Python 的身影. Python 有两个主要的 ...

  2. 两种常用文件分享方式 - 网络硬盘快速分享, 点对点的文件共享 BitTorrent Sync

    普通的用户经常通过电子邮件.QQ传递等方式进行文件的分享,但是由于不同的网络环境有的时候可能会有不同的限制,所以我们就需要寻找其他的方式来替代.今天就为大家推荐两个既常用又与众不同的分享方式. 中国论 ...

  3. 苹果ATS 豁免摆乌龙?

    现象 我们的App已经完成了NA部分的ATS适配.网页端由于有使用到第三方的页面,所以开启了网页的豁免权限.关于如何开启豁免及方法,可以参考喵神的Blog最终,我们的适配参数为: NSAllowsAr ...

  4. bzoj1214 [HNOI2004]FTP服务器

    题目挺复杂的. 但有一点好,就是这题没数据,交个空程序就好了. begin end.

  5. 【大数据】Zookeeper学习笔记

    第1章 Zookeeper入门 1.1 概述 Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目. 1.2 特点 1.3 数据结构 1.4 应用场景 提供的服务包括:统 ...

  6. 解题:AT2064 Many Easy Problems&EXNR #1 T3 两开花

    题面 两道题比较像,放在一起写了,后者可以看成前者的加强版 (sto ztb orz) 先看AT那道题 考虑计算每个点的贡献,用容斥计算:每个点没有贡献当且仅当选的所有点都在以他为根时的一个子节点的子 ...

  7. AIO + ByteBufferQueue + allocateDirect 终于可以与NIO的并发性能达到一致。

    看到这个标题,你可能会惊讶,相比NIO,AIO不就是为了在高并发的情况下代替NIO的吗? 是的,没错,但是在并发不高的情况下,AIO的性能表现很多时候还不如NIO. 在一台机子上用ab进行并发压力测试 ...

  8. asp.net中SQL语句太长,怎么换行写?

    http://bbs.csdn.net/topics/390639485?page=1 string strfac="insert into CarInfo values('"+T ...

  9. xgboost入门与实战(原理篇)

    sklearn实战-乳腺癌细胞数据挖掘 https://study.163.com/course/introduction.htm?courseId=1005269003&utm_campai ...

  10. Tomcat权威指南-读书摘要系列7

    配置 conf目录下的主要配置文件 server.xml Tomcat主配置文件 web.xml servlet与其他适用于整个Web应用程序设置的配置文件,必须符合servlet规范的标准格式 to ...