[c++语法]类
什么是类
类 是 面向对象的基础。c里面是没有对象的,只有数据,即静态的死物。
从面向过程升级到面向对象后,有了对象的概念,对象是数据与方法的合体,是动态的活物。
类代表着一类事物的特征。而对象,是类的具体化,实例化。
类的声明与定义
一般来说,类的声明在相应的头文件中,类的定义在相应的源文件中。这样实现了接口与实现的分离。
//Dog.h #ifndef _DOG_H_
#define _DOG_H_ #include <string>
#include <iostream> class Dog { //类的声明
public: //公共成员
Dog(){} //默认构造函数
Dog(float weight) : weight(weight){ //可以隐式转换
sex = true;
}
explicit Dog(bool isMale) : sex(isMale){} //explicit 修饰不可以隐式转换
Dog(float weight , bool sex); Dog(const Dog &dog) : weight(dog.weight) , sex(dog.sex) , name(dog.name) , power(dog.power){}; //复制构造函数
Dog& operator=(const Dog &dog){ //赋值函数
weight = dog.weight;
sex = dog.sex;
} ~Dog(){ //析构函数 } void bellow();
inline std::string toString(); // 类定义外部的inline方法,方法定义必须与类定义在同一个文件
float getWeight() const{ //类定义内部定义的方法,默认为inline
return weight;
} void info(std::ostream& out); static int getNum() { //静态成员函数
return num;
} // int t1 = 1; //error , 类定义中成员变量不能初始化。
const static int t2 = 3; //只有 const static 类型才能在类定义中初始化。
static int t3; //static 成员变量初始化写在源文件中。
protected: //保护成员 private: //私有成员
float weight;
bool sex;
mutable int power; //mutable类型变量,在const 对象中依然可以修改。
std::string name;
static int num; // 静态成员变量 }; std::string Dog::toString(){ // 类定义外部的inline方法,方法定义必须与类定义在同一个文件
std::string str("Dog[name=");
str+=name;
str+=",weight=";
str+=weight;
str+=",sex=";
str+=sex;
str+="]";
return str;
} #endif
//Dog.cpp #include "Dog.h"
#include <iostream> void Dog::bellow(){ //类方法的定义
std::cout<<"wang wang wang"<<std::endl;
} void Dog::info(std::ostream& out){
out << "Dog[name=" << name <<",weight=" << weight <<",sex=" << sex <<"]" << std::endl;
} //const int Dog::t2; //const static 成员定义。
int Dog::t3 = 10; //static 成员初始化。
类的实例化
Dog d(1.0f);
Dog *d2 = new Dog(1.0f);
类的初始化:构造函数
当创建一个类对象时,构造函数将会被调用。
如:
语句 Dog d(1.0f);
Dog *d2 = new Dog(1.0f);
会使编译器调用 Dog(float w) : weight(w) {} 来初始化对象
构造函数分为3部分:函数签名(函数名加形参列表),即 Dog(float w)
初始化列表 冒号与大括号之间的部分为初始化列表。即 weight(w)
构造函数 即大括号中的内容。
构造函数执行时,先执行初始化列表,然后再执行构造函数。
先执行初始化列表:
初始化列表的任务是 初始化类中的成员变量。顺序是按照类中声明的顺序挨个初始化。
类类型成员初一定初始化,在初始化列表的,就用初始化列表中的初始化方法。不在初始化列表的,就调用类的默认构造函数。 从这里可以看出,没有默认构造函数的类类型,引用类型,const类型 必须在初始化列表。
内置类型和复合类型的不一定初始化,如果在初始化列表,就用初始化列表中的初始化方法。如果不在,就得看对象的位置,全局的初始化,局部的不初始化。
然后再执行构造函数
//playdog.cpp #include <iostream>
#include <cstdlib>
#include "Dog.h" Dog gloabDog; int main(){
Dog localDog;
gloabDog.info(std::cout);
localDog.info(std::cout); return EXIT_SUCCESS;
}
输出:
由此,可以看出对象是局部变量的情况下,没有出现在相应初始化列表的内置类型类成员没有初始化。
复制构造函数与赋值函数
复制构造函数是一个特殊的构造函数。它只有一个参数,相同类对象的引用。
赋值函数是将相同类的对象赋值给对象。
Dog(const Dog &dog) : weight(dog.weight) , sex(dog.sex) , name(dog.name) , power(dog.power){}; //复制构造函数
Dog& operator=(const Dog &dog){ //赋值函数
weight = dog.weight;
sex = dog.sex;
}
Dog d1;
Dog d2(d1); //调用复制构造函数
Dog d3 = d1; //调用复制构造函数
Dog d4;
d4 = d1; //调用赋值函数
赋值构造函数,赋值函数,如果不写的话,编译器会默认一个。系统默认的 就是将成员变量按照声明的顺序挨个复制一遍。
复制构造函数出现的地方:
1,上面的显示调用。
2,对象作为方法参数传入, 对象作为方法返回值返回。
3,初始化容器
4,初始化数组元素
Dog d2(d1); //显示调用
std::string caculate(std::string str1 , std::string str2); //形参,返回值
std::vector<std::string> svec(5); //先调用string的默认构造函数生成一个string临时对象,然后调用5次复制构造函数来初始化容器
std::string[] strs = { //显示调用构造函数生成临时对象,然后调用复制构造函数来初始化数组元素
string("hello"),
string("word")
}
析构函数
析构函数是删除对象时调用的方法,用来释放对象占用的资源。析构函数是无论是否编写,编译器都会默认一个析构函数。这个默认的析构函数就是按照成员变量声明的顺序的倒序挨个释放资源,如果是类类型,就调用该对象的析构函数。
调用析构函数的时候,先调用用户写的,然后再调用编译器默认的。
三法则
复制构造函数,赋值函数,析构函数, 这三个函数什么时候需要写呢?
一般来说,类中有指针成员变量,或者有需要特殊控制的资源,就需要写。这是3个函数一定是同时需要写,或同时不需要写。静态成员
类中static 修饰静态成员。静态成员属于类,不属于任何一个对象。
所以 static方法中不能使用 this,不能访问非静态方法,非静态变量。
静态成员变量在类定义时初始化。定义在类定义中,初始化在类方法实现源文件中。
c++ primer 中说 const static 成员在类定义中声明初始化,但是还必须在类实现源文件中在空初始化一次。
如: 类定义中 const static int t2 = 3; 但是还必须在Dog.cpp中 const int t2;
但在我的机器上,Dog.cpp中不加这一句仍然没问题。
static 成员的调用
int main(){
std::cout << Dog::t3 << std::endl;
std::cout << Dog::t2 << std::endl;
return EXIT_SUCCESS;
}
类的封装
这里由类的成员访问限定符(member access specifier)实现。
public 任意都可访问。
private 只有本类可访问
protected 不能被类外访问(这点与私有成员类似),但可以被派生类的成员函数访问。
默认内联函数
c++中,inline表示内联函数。在程序调用这些成员函数时,并不是真正地执行函数的调用过程(如保留返回地址等处理),而是把函数代码嵌入程序的调用点。这样可以大大减少调用成员函数的时间开销。
C++要求对一般的内联函数要用关键字inline声明,但对类内定义的成员函数,可以省略inline,因为这些类内定义成员函数已被隐含地指定为内联函数。
如 float getWeight() const 就默认为内联函数了。
不在类定义内定义的内联函数,必须在类定义同一个文件中定义。
如 inline std::string toString(); 必须也在Dog.h 中定义,如果在Dog.cpp中定义,就会出现编译错误。
构造函数隐式转换
只有一个形参的构造函数可以参与隐式转换。
如 因为有构造函数 Dog(float weight)
Dog d = 1.0f;
编译器会把 float 类型 的 1.0f 通过 Dog(float weight) 隐式转换成一个临时的 Dog 类型对象,然后赋值给d.
explicit 修饰构造函数 可以禁止 隐式转换。
[c++语法]类的更多相关文章
- oc 基本语法 类 静态变量 常量
// // ReViewClass.h // hellowWorld // 本类是oc复习练手类 // Created by hongtao on 2018/3/26. // Copyright © ...
- ES6深入浅出-8 新版的类(下集)-1.简单语法
回顾 当你声明一个空的对象obj的时候,会生成一块内存这个内存里面什么都没有,自由__proto__存在401的地址. 也就是Object的protototype在内存中的地址 类 通过函数创建类.这 ...
- swift学习笔记3——类、结构体、枚举
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- IOS基础之 (三) 类的声明和对象的创建
一 OC类的声明和实现语法 1.接口的声明 @interface NewClassName: ParentClassName { 实例变量 ... } 方法的声明 ... @end //...表示省略 ...
- Ruby学习: 类的定义和实例变量
ruby是完全面向对象的,所有的数据都是对象,没有独立在类外的方法,所有的方法都在类中定义的. 一.类的定义语法 类的定义以 class 关键字开头,后面跟类名,以 end标识符结尾. 类中的方法以 ...
- Swift 的类、结构体、枚举等的构造过程Initialization(下)
类的继承和构造过程 类里面的全部存储型属性--包含全部继承自父类的属性--都必须在构造过程中设置初始值. Swift 提供了两种类型的类构造器来确保全部类实例中存储型属性都能获得初始值,它们各自是指定 ...
- C++_进阶之函数模板_类模板
C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...
- swift 学习- 10 -- 类和结构体
// '类和结构体' 是人们构建代码所使用的一种通用且灵活的构造体, 我们可以使用完全相同的语法规则来为 '类和结构体' 定义属性 (变量 和 常量) 和添加方法, 从而扩展 类和结构体 的功能 // ...
- java基础语法2.
第二章 2.1 class文件的生成 java文件为源代码文件 class为程序. class文件实时修改. eclipse自动生成. project下面clean. 2.2 jar文件 如何将有用的 ...
随机推荐
- ASP.NET中操作SQL数据库
在WebConfig中配置数据库连接字符串,代码如下: <connectionStrings> <add name="ConnectionString&qu ...
- Activity的绘制流程简单分析(基于android 4.0源码进行分析)
要明白这个流程,我们还得从第一部开始,大家都知道 在activity里面 setcontentview 调用结束以后 就可以看到程序加载好我们的布局文件了,从而让我们在手机上看到这个画面. 那么我们来 ...
- 终于懂了:FWinControls子控件的显示是由Windows来管理,而不是由Delphi来管理(显示透明会导致计算无效区域的方式有所不同——透明的话应减少剪裁区域,所以要进行仔细计算)
在研究TCustomControl的显示过程中,怎么样都找不到刷新FWinControls并重新显示的代码: procedure TWinControl.PaintHandler(var Messag ...
- 图片转换成Base64编码集成到html文件
首先为什么要这么做? 原因很简单这样可以减少与服务器的请求,当然对于一些浏览器并不支持,如IE8.通常用在手机版网站中,具体转化方法如下: 1.在线打开Base64的编码器将图片编码成Base64 ...
- Coin Toss
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=31329#problem/G 使用二维数组f[ i ] [ j ] 表示前i 位中有j个 ...
- HDU3572_Task Schedule(网络流最大流)
解题报告 题意: 工厂有m台机器,须要做n个任务.对于一个任务i.你须要花费一个机器Pi天,并且,開始做这个任务的时间要>=Si,完毕这个任务的时间<=Ei. 对于一个任务,仅仅能由一个机 ...
- Java内部类——成员内部类
成员内部类的意思就是,一个外层类里面包含着一个非static的class,举例如下: class OuterClass { //变量,函数定义... class InnerClass { //变量,函 ...
- call、apply以及bind
call与apply都可以改变js的this指向,两者最主要的区别就是使用时传参的不同,apply的参数可以以数组的形式传进来,但是call方法的参数必须要一个一个的传进来,就像这样. func.ca ...
- Android中View绘制优化之三---- 优化View
本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 译三: 优化视图 关于如何设计自定义View以及响应触摸时间等,请看Android developer : 地 ...
- javascript事件委托,事件代理,元素绑定多个事件之练习篇
<ul id="parent-list"> <li id="post-1">item1</li> <li id=&qu ...