类的定义

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

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

  定义在类内部的函数是隐式的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. 如何让搜索引擎抓取AJAX内容?

    越来越多的网站,开始采用"单页面结构"(Single-page application). 整个网站只有一张网页,采用Ajax技术,根据用户的输入,加载不同的内容. 这种做法的好处 ...

  2. 使用doxygen静态分析开源代码

    doxygen是一款生成开源代码说明文件的工具,因为不需要编译源码,用作代码的分析也十分方便. 一.安装 sudo apt-get install graphviz sudo apt-get inst ...

  3. hdwiki 部署

    1.安装wamp 集成环境(部署过程出现的环境问题请搜索我的另外一篇文章 <wamp安装失败原因大全>)2.到 http://kaiyuan.hudong.com/download/ 下载 ...

  4. 【题解】 [HNOI/AHOI2018]道路 (动态规划)

    懒得复制,戳我戳我 Solution: \(dp[i][j][k]\)以\(i\)为子树根节点,到根节点中有\(j\)条公路没修,\(k\)条铁路没修,存子树不便利和 \(dp[i][j][k]=mi ...

  5. 【bzoj1044】木棍分割

    Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长 ...

  6. 【转】巧用CAT706做掉电检测

    相信大家都会遇到这样的情况,当你正在敲一份文档或一段代码时,啪的一下停电啦,我擦……,我的代码……,我的图纸……,我刚写好的文章…….但是在嵌入式系统中也会遇到类似的情况,通常会导致嵌入式系统数据,程 ...

  7. Hadoop生态圈-Azkaban部署实战

    Hadoop生态圈-Azkaban部署实战 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.  一.Azkaban部署流程 1>.上传azkaban程序并创建解压目录 [yinz ...

  8. saltstack主机管理项目【day39】:主机管理项目开发

    项目目标 salt state.apply -h "ubuntu,centos" -g "ubuntu,centos" -f "ubuntu,cent ...

  9. SQL记录-PLSQL日期与时间

    PL/SQL日期及时间 PL/SQL提供两个日期和时间相关的数据类型: 日期时间(Datetime)数据类型 间隔数据类型 datetime数据类型有: DATE TIMESTAMP TIMESTAM ...

  10. SHELL (1) —— shell脚本入门

    摘自:Oldboy Linux运维——SHELL编程实战 SHELL Shell是一个命令解释器,解释执行用户输入的命令及程序等,用户每输入一条命令,Shell就解释执行一条.这种从键盘以输入命令,就 ...