什么是类

类 是 面向对象的基础。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++语法]类的更多相关文章

  1. oc 基本语法 类 静态变量 常量

    // // ReViewClass.h // hellowWorld // 本类是oc复习练手类 // Created by hongtao on 2018/3/26. // Copyright © ...

  2. ES6深入浅出-8 新版的类(下集)-1.简单语法

    回顾 当你声明一个空的对象obj的时候,会生成一块内存这个内存里面什么都没有,自由__proto__存在401的地址. 也就是Object的protototype在内存中的地址 类 通过函数创建类.这 ...

  3. swift学习笔记3——类、结构体、枚举

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  4. IOS基础之 (三) 类的声明和对象的创建

    一 OC类的声明和实现语法 1.接口的声明 @interface NewClassName: ParentClassName { 实例变量 ... } 方法的声明 ... @end //...表示省略 ...

  5. Ruby学习: 类的定义和实例变量

    ruby是完全面向对象的,所有的数据都是对象,没有独立在类外的方法,所有的方法都在类中定义的. 一.类的定义语法 类的定义以 class 关键字开头,后面跟类名,以 end标识符结尾. 类中的方法以 ...

  6. Swift 的类、结构体、枚举等的构造过程Initialization(下)

    类的继承和构造过程 类里面的全部存储型属性--包含全部继承自父类的属性--都必须在构造过程中设置初始值. Swift 提供了两种类型的类构造器来确保全部类实例中存储型属性都能获得初始值,它们各自是指定 ...

  7. C++_进阶之函数模板_类模板

     C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...

  8. swift 学习- 10 -- 类和结构体

    // '类和结构体' 是人们构建代码所使用的一种通用且灵活的构造体, 我们可以使用完全相同的语法规则来为 '类和结构体' 定义属性 (变量 和 常量) 和添加方法, 从而扩展 类和结构体 的功能 // ...

  9. java基础语法2.

    第二章 2.1 class文件的生成 java文件为源代码文件 class为程序. class文件实时修改. eclipse自动生成. project下面clean. 2.2 jar文件 如何将有用的 ...

随机推荐

  1. cocos2d-x游戏开发系列教程-中国象棋05-开始游戏

    前情回顾 通过CCMainMenu的init函数,已经把所有的按钮,棋子都摆放完毕了,但是这个时候,棋子是不能走动的,只有在开始游戏之后才能移动棋子. 点击

  2. hdu4717 The Moving Points(二分做法)

    这道题看了大家都是用三分做的,其实这道题也是可以用二分来做的,就是利用一下他们的单调性. 对于N个点,总共要考虑N(N+1)/2个距离,距离可以用二次函数表示,而且开口都是向上的. 下面具体说一下二分 ...

  3. Android Socket 开发技术

    根据之前的经验,应用软件的网络通信无非就是Socket和HTTP,其中Socket又可以用TCP和UDP,HTTP的话就衍生出很多方式,基础的HTTP GET和POST请求,然后就是WebServic ...

  4. 终于实现samba可写不可删除

    通过szxsztszk的提示 今天终于实现了linux可写不可删除的要求. 同时运用了POSIX ACL 我们公司的要求是这样的[color=Red](我只做出我公司要求的步骤,不同的要求,稍加改正即 ...

  5. 用c++开发基于tcp协议的文件上传功能

    用c++开发基于tcp协议的文件上传功能 2005我正在一家游戏公司做程序员,当时一直在看<Windows网络编程> 这本书,把里面提到的每种IO模型都试了一次,强烈推荐学习网络编程的同学 ...

  6. ZJUT 1423 地下迷宫(期望DP&高斯消元)

    地下迷宫 Time Limit:1000MS  Memory Limit:32768K Description: 由于山体滑坡,DK被困在了地下蜘蛛王国迷宫.为了抢在DH之前来到TFT,DK必须尽快走 ...

  7. USACO inflate

    全然背包,转化为0/1背包 dp[i, j] = max(dp[i-1, j], dp[i, j - minutes[i]] + points[i]) /* ID:kevin_s1 PROG:infl ...

  8. uva 620 Cellular Structure

    题目连接:620 - Cellular Structure 题目大意:给出一个细胞群, 判断该细胞的可能是由哪一种生长方式的到的, 输出该生长方式的最后一种生长种类, "SIMPLE&quo ...

  9. asp.net2.0安全性(1)--用户角色篇(代码实现2)--转载来自车老师

    加载所有用户 MembershipUserCollection user = Membership.GetAllUsers(); listUser.DataSource = user; listUse ...

  10. backbone入门小例子

    最近听了个backbone的分享,为了避免听不懂,就先做了个小例子 例子很简单,效果如下 基本视图模板: <script type="tex/template" id=&qu ...