文章目录

  • 抽象和类
    • c++中的类
    • 定义成员函数
  • 类的构造函数和析构函数
    • 成员名和参数名
    • 使用构造函数
    • 初始化列表
  • 默认构造函数
    • 析构函数
    • const成员函数
    • 构造函数和析构函数小结
  • this指针
  • 对象数组
  • 类作用域
    • 作用域为类的常量
    • 作用域内枚举

抽象和类

c++中的类

c++程序员将接口放在头文件中,并将实现放在源代码文件中。
关键字private和public描述了对类成员的访问控制。使用类对象的程序都可以直接访问公有部分,但只能通过公有成员函数(或友元函数)来访问对象的私有成员。
什么是封装?
公有接口表示设计的抽象组件。将实现细节放在一起并将他们与抽象分开被称为封装。数据隐藏(将数据放在类的私有部分中)是一种封装,将实现细节隐藏在私有部分中,也是一种封装,将类函数定义和类函数声明放在不同文件中也是封装。
不必在类声明中使用关键字private,因为这是类对象的默认访问控制。

定义成员函数

  • 定义成员函数,使用作用域解析运算符::来标识函数所属的类
  • 类方法可以访问类的private组件。

例如:

void Stock::update(double price)
class Stock
{void set_tot()
{total_val=shares *share_val}
};

其定义位于类声明中的函数都将自动成为内联函数,Stokc::set_tot是一个内联函数,也可以在类声明外定义成员函数,只需加上inline限定符
所创建的每个新对象都有自己的存储空间,用于存储其内部变量和类方法。

类的构造函数和析构函数

class Stock
{public:Stock(const string& co, int a, double b){s1 = co;aa = a;bb = b;}void show(){cout << s1 << " " << aa << " " << bb;}
private:int aa;double bb;string s1;
};
int main()
{Stock a("yes", 1, 2.0);a.show();
}

可以在函数外面定义构造函数,例如:

class Stock
{public:Stock(const string& co, int a, double b);void show(){cout << s1 << " " << aa << " " << bb;}
private:int aa;double bb;string s1;
};
int main()
{Stock a("yes", 1, 2.0);a.show();
}
Stock::Stock(const string& co, int a, double b)
{s1 = co;aa = a;bb = b;
}

成员名和参数名

将类成员名称用作构造函数的参数名是错误的,例如

class Stock
{public:
Stock(int a,int b)
{}
private:
int a,b;

为避免这种混乱,一种常见的做法是在数据成员名中使用m_前缀:

class Stock
{private:
string m_company;
long m_shares;
}

或者是在成员名后面使用后缀_。

使用构造函数

c++提供了两种构造函数来初始化对象。第一种是显式地调用构造函数:

Stock food=Stock("dsfsd",1,2.0)

这将s1设置为"dsfsf",aa为1,bb为2.0,以此类推,另一种方式隐式地调用构造函数:

Stock food("dsfds",1,2.0)

这与上面的显式是等价的。
下面是将构造函数和new一起使用的方法:

stock* pstock= new Stock("dsfsd",1,2.0)

这条语句创建一个Stock对象,将其初始化为参数提供的值,并将该对象的地址赋给pstock指针。

Stock a("yes", 1, 2.0);a.Stock("yes", 1, 2.0);

不能使用对象来调用构造函数,构造函数被用来 创建对象。

初始化列表

如果数据成员是const或者引用的话,必须采用舒适化列表例如:

class Time
{private:const int hours, minutes;
public:Time():hours(0),minutes(0){}Time(int h, int m):hours(h),minutes(m){}

默认构造函数

例如:

Stock fluffy_the_cat;

它是默认构造函数的隐式版本,不做任何工作。
默认构造函数没有参数,因为声明中不包含值。
当且仅当没有定义任何构造函数时,编译器才会提供默认构造函数。为类定义了构造函数后,程序员就必须为他提供默认构造函数。如果提供了非默认构造函数,但没有提供默认构造函数,则下面的声明将出错

stock stock1;

这样做的原因可能是想禁止创建为初始化的对象。然而,如果要创建对象,而不显式地初始化,则必须定义一个不接受任何参数的默认构造函数。定义默认构造函数优两种方式,一种是给已有构造函数的所有参数提供默认值:

Stock(const string &co="fdsfds",.int n=0,double pr=0.0);

这个注意是在函数原型里面加默认值。
还有一种方法是为Stock类定义一个默认构造函数:

Stock ::Stock()
{s1="dsf"
aa=1;
bb=1.0;
}

不要同时采用这两种方式会报错。

析构函数

与构造函数不同的是,析构函数没有参数,因此Stock的析构函数的原型必须是这样的:

~Stock();

如果创建的是静态存储类对象,则其析构函数将在程序结束时自动被调用,如果创建的是自动存储对象,则其析构函数将在程序执行完该代码块时自动被调用,如果对象是通过new创建的,当使用delete来释放内存时,析构函数自动被调用,程序可以创建临时对象来完成特定的操作,程序将在结束对该对象的使用时自动调用其析构函数。

class Stock
{public:~Stock(){cout << "yes";}};
int main()
{Stock stock2 = Stock();
}

这种方式是调用构造函数来创建一个临时对象,然后将该临时对象复制到stock2中并丢弃它,这将为临时对象调用析构函数,因此会输出yes.

class Stock
{public:string b;Stock(string a){b = a;}~Stock(){cout << b << endl;}};
int main()
{Stock stock2("one");Stock stock3("two");
}

由于自动变量被放在栈中,因此后创建的对象将最先被删除。

Stock stock2 = Stock("one");Stock stock1;stock1 = Stock("two");

这两条语句有根本性的差别,第一条语句是初始化,它创建有指定值的对象,可能会创建临时对象(也可能不会),我操作的是不会的,第二条语句是赋值,像这样在赋值语句中使用构造函数总会导致在赋值前创建一个临时对象。
如果既可以通过初始化,也可以通过赋值来设置对象的值,则应采用初始化方式。效率更高。

const成员函数

class Stock
{public:string b;Stock(string a){b = a;}void show(){cout << b << endl;}
};
int main()
{const Stock stock2 = Stock("one");stock2.show();
}

对于c++来说,编译器将拒绝第二行,因为show()的代码无法保证调用对象不被修改,show()使用的对象是由方法调用隐式提供的。需要新的一种语法来保证函数不会修改调用对象。c++的解决办法是将const关键字放在函数的括号后面。例如:

void show()const;

同样函数的定义的开头也应这样:

void Stock::show()const

以这种方式声明和定义的类函数被称为const成员函数。只要类方法不修改调用对象,就应将其声明为const。

构造函数和析构函数小结

如果构造函数只有一个参数,则将对象初始化为一个与参数的类型相同的值时,该构造函数将被调用。例如:

class Bozo
{public:int a;Bozo(int age){a = age;}
};
int main()
{Bozo one = 32;cout << one.a;
}

这样也能将one初始化,不过它可能会让人很难受,会在第十一章介绍关闭这项特性的方式。
默认构造参数可以没有任何参数;如果有,则必须给所有参数提供默认值。
对于未初始化的对象,程序将使用默认构造函数来创建:

Bozo bubi;
Bozo *pb=new Bozo;

如果构造函数使用了new,则必须提供使用delete的析构函数。

this指针

假设要对两个对象进行比较,例如

const max1& compare(const max1& s)const

可以这样写:

max1 one(3);max1 two(4);two.compare(one);

对于two.compare(one)来说,这种格式显式地访问one,隐式地访问two.
对于two来说他有名字s,但是对于one来说却没有名字,c++解决这种问题的方法是:使用被称为this的特殊指针,this指针指向用来调用成员函数的对象。例如:

class max1
{public:int a;max1(int b){a = b;}const max1& compare(const max1& s)const {if (s.a > a){return s;}else{return *this;}}
};int main()
{max1 one(3);max1 two(4);two.compare(one);cout << two.a;
}

对象数组

例如:

Stock mystuff[4];

上述声明,这个类如果没有定义任何构造函数,将使用不执行任何操作的隐式默认构造函数,可以用构造函数来初始化数组元素例如:

class max1
{public:int a;max1(int b){a = b;}
};int main()
{max1 arr[4] = { max1(1),max1(2),max1(3),max1(4) };}

但是要对所有元素调用构造函数,除非有默认构造函数。

类作用域

作用域为类的常量

类声明可能使用字面值为30来指定数组的长度,由于该常量对于所有对象都是相同的,因此创建一个由所有对象共享的常量是个不错的注意。您可能以为这样做可行:

class Bakery
{private:const int Months = 12;double costs [Months];
};

这样是不行的,因为声明类只是描述了对象的形式,没有创建对象。因此在创建对象前,将没有用于存储的空间。下面有两种方式:
第一种方式是在类中声明一个枚举。例如:

class Bakery
{private:enum{Months=12};double costs [Months];
};

由于这里只是为了创建符号常量,因此不需要提供枚举名。
第二种方法是使用关键字static:

class Bakery
{private:static const int Months = 12;double costs [Months];
};

该常量将于其他静态变量存储在一起,而不是存储在对象中。

作用域内枚举

两个枚举定义的枚举量可能发生冲突。例如:

enum egg{small,medium,large,jumbo};enum t_shirt{small,medium,large,xlarge};

c++11提供了一种新枚举,其枚举量的作用域为类。例如:

enum class ege{small,medium,large,jumbo};enum class t_shirt{small,medium,large,xlarge};

也可以使用关键字struct来代替class。

enum struct ege { small, medium, large, jumbo };enum struct t_shirt { small, medium, large, xlarge };

无论哪种方式都要使用限定名来限定枚举量:

    enum struct ege { small, medium, large, jumbo };enum struct t_shirt { small, medium, large, xlarge };ege one = ege::small;t_shirt two = t_shirt::large;

c++11还提高了作用域内枚举的类型安全。在有些情况下,常规枚举将自动转换为整形,如将其赋给int变量或用于比较表达式时,但作用域内枚举不能隐式地转换为整形:

enum ege{small,medium,large,jumbo};enum class t_shirt{small,medium,large,xlarge};ege one = medium;t_shirt rolf = t_shirt::large;int king = one;int ring = rolf;fasleif (king < jumbo)///allow{}if (king < t_shirt::medium)///not allowed{}int Frodo = int(t_shirt::small);///allowed

必要时可以进行显式类型转换。
枚举用底层整形表示,在c++98中,如何选择取决于实现,因此包含枚举的结构的长度可能随系统而异,对于作用域内枚举,c++11消除了这种依赖性,默认情况下,c++11作用域内枚举的底层类型为int。另外还提供了一种语法,可以做出不同的选择:

enum etype2 : short { small ,medium,large,xlarge };

c++ primer plus给的是

enum class : short pizza { small ,medium,large,xlarge };

会报错。
应该是这样才对

enum class pizza :short { small ,medium,large,xlarge };

下面是使用类来实现stack;

#include<iostream>
#include"stack.h"
using namespace std;
int main()
{Stack st;char ch;int po;while (cin >> ch && toupper(ch) != 'Q'){while (cin.get() != '\n'){continue;}if (!isalpha(ch)){cout << '\a';continue;}switch (ch){case'A':case'a':cout << "Enter a PO number to add:";cin >> po;if (st.isfull()){cout << "stack alreat full\n";}else{st.push(po);}break;case 'p':case'P':if(st.isempty()){cout << "stack already empty\n";}else{st.pop(po);cout << "po#" << po << "popped\n";}break;}}}
#ifndef Stack_H
#define Stack_H
class Stack
{private:enum{MAX=5};int items[MAX];int top;
public:Stack();bool isempty()const;bool isfull()const;bool push(const int& x);bool pop(int &x);
};
#endif
#include"stack.h"
#include<iostream>
using namespace std;
Stack::Stack()
{top = 0;
}
bool Stack::isempty()const
{return top == 0;
}
bool Stack::isfull()const
{return top == MAX;
}
bool Stack::push(const int& x)
{if (top < MAX){items[top++] = x;return true;}return false;
}
bool Stack::pop(int& x)
{if (top > 0){x = items[--top];return true;}return false;
}

C++ --对象和类相关推荐

  1. 客快物流大数据项目(五十六): 编写SparkSession对象工具类

    编写SparkSession对象工具类 后续业务开发过程中,每个子业务(kudu.es.clickhouse等等)都会创建SparkSession对象,以及初始化开发环境,因此将环境初始化操作封装成工 ...

  2. Java 对象和类 的理解

    学而时习之,温故而知新. 对象: 对象是类的一个实例,有状态和行为 类: 类为对象定义属性和行为 识别对象和类, 自己的的知识里面 一般 new 之后的是对象, class后面的是类 对象的特征: 1 ...

  3. Swift中文教程(五)--对象和类

    原文:Swift中文教程(五)--对象和类 Class 类 在Swift中可以用class关键字后跟类名创建一个类.在类里,一个属性的声明写法同一个常量或变量的声明写法一样,除非这个属性是在类的上下文 ...

  4. js之数组,对象,类数组对象

    2019独角兽企业重金招聘Python工程师标准>>> 许久不写了,实在是不知道写点什么,正好最近有个同事问了个问题,关于数组,对象和类数组的,仔细说起来都是基础,其实都没什么好讲的 ...

  5. Java学习_day008面向对象(OOP):对象和类

    面向对象:OO 面向对象的分析:OOA 面向对象的设计:OOD 面向对象分析与设计:OOAD--目标 面向对象的编程:OOP--起始点 高质量代码的要求(OO终极目标):复用性好.拓展性好.维护性好. ...

  6. 【学习笔记】【oc】类和对象及类的三大基本特征

    1.类和对象 类是抽象化,对象是具体化. (1)定义类: 分为两个步骤,类的声明:定义类的成员变量和方法:@interface 用于声明定义类的接口部分,@end表面定义结束:. 成员变量的定义:{} ...

  7. javascript对象、类与原型链

    js是一个基于对象的语言,所以本文研究一下js对象和类实现的过程和原理. 对象的属性及属性特性 下面是一个对象的各个部分: var person = {name: "Lily",a ...

  8. typeScript面试必备之-通识七:typeScript中的可索引接口(数组,对象)+类类型接口...

    可索引接口:数组.对象的约束 (不常用) ts定义数组的方式 var arr:number[]=[2342,235325]var arr1:Array<string>=['111','22 ...

  9. 一、静态工厂的第四个优点是返回对象的类可以根据输入参数的不同而不同。...

    静态工厂的第四个优点是返回对象的类可以根据输入参数的不同而不同. 声明的返回类型的任何子类都是允许的. 返回对象的类也可以随每次发布而不同. EnumSet类(条目 36)没有公共构造方法,只有静态工 ...

  10. java类和对象实例对象_Java类、对象和实例的理解

    最近在看Python,这门面向对象的语言又引起了类的引用.对象和实例这些概念之间的纠结,我按照自己的理解总结了一下Java里三者的关系,如果有不对的地方还希望大家指出. 类的引用和对象的概念没什么好弄 ...

最新文章

  1. 在Uubuntu 14.04 64bit上搭建NumPy函数库环境
  2. Java语言程序设计(基础篇)第八章(2 19 36)
  3. 程序员编程艺术第二章
  4. bp神经网络_BP 神经网络驱动的手写体数字识别软件 EasyOCR
  5. boost::histogram::accumulators用法的测试程序
  6. C++map容器遍历删除:cannot increment value-initialized map/set iterator
  7. fedora 20 中关闭防火墙
  8. 人教版三年级下册计算机课教案,人教版三年级下册19课教案
  9. 机器学习系列------1. GBDT算法的原理
  10. 多模态 | 复旦推出跨视觉语言模态预训练模型,并达到SOTA
  11. select .. into输出单/多行
  12. 系统同传软件_影视翻译软件可实时在线翻译多国语言
  13. 爱快服务器怎么重置系统,爱快软路由 备份设置以及恢复备份设置教程-路由器怎么恢复出厂设置...
  14. islower()方法
  15. 微擎支付返回商户单号_扫码枪轻轻一扫,瞬间扣款,支付背后的原理原来这么简单...
  16. java使用阿里云发送通知短信
  17. Linux kernel panic 问题解决方案
  18. CDATA标签的用法
  19. 在HTML中添加视频的代码
  20. 京东网京东快报超级链接验证

热门文章

  1. 最新app源码下载:200款优秀Android项目源码
  2. modbus通讯失败_你以为你真的了解Modbus 通信协议?
  3. 2017华为软件精英挑战赛思路分析
  4. JSinput上传图片文件转base64
  5. 王招治计算机财务管理,计算机财务管理——以Excel为分析工具
  6. 算法设计与分析第二章习题解答与学习指导(第2版)屈婉婷 刘田 张立昂 王捍贫编著 清华大学出版社
  7. 基于SSM实现图书借阅管理系统-毕业设计
  8. 近义词替换-近义词替换器-免费近义词替换器
  9. java项目报告书_Java项目报告模版.doc
  10. java支付系统,三方支付系统,四方支付系统