[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文件 如何将有用的 ...
随机推荐
- 记一次在Tomcat部署项目后无法启动该项目的例子
在一次正常部署后,发现在Tomcat的管理中无法将该项目启动起来,并在Tomcat的日志文件localhost.log中发现以下错误信息: java.lang.NoSuchMethodError: o ...
- c语言,数组和指针
概要: 1.普通数组与指针 2.数组指针 3.指针的数组 数组是一个由(同一类型)连续元素组成的预先分配的内存块:指针是一个对任何位置的元素的引用. 数组自动分配空间,但不能重分配或改变大小:指针必须 ...
- _splitpath / _wsplitpath 将绝对路径分割为盘符、路径、文件名、扩展名。
今天分享下一个路径分割的API,可以将一个完整的绝对路径分割为: 盘符(包括冒号:) 路径(包含前面&后面的\,不含盘符&文件名) 文件名(不含扩展名) 扩展名(包含前面的.) 先不说 ...
- VPN指定某个程序,其实是改路由表(赛风支持VPN和SSH和SSH+模式)
其实就是使用IE代理的意思,方法有很多.最简单的就是读取注册表中的代理信息.具体找;\Software\Microsoft\Windows\CurrentVersion\Internet Settin ...
- AIX用户管理
用户和组管理 /etc/passwd /etc/security/.profile /etc/security/limits /etc/security/passwd ...
- 能够返回运行结果的system函数加强版本号
/********************************************************************* * Author : Samson * Date ...
- 设计模式6:Composite
Entry.java: package gendwang.cisco.com; public abstract class Entry { private int height = 0; privat ...
- NLP | 自然语言处理 - 标注问题与隐马尔科夫模型(Tagging Problems, and Hidden Markov Models)
什么是标注? 在自然语言处理中有一个常见的任务,即标注.常见的有:1)词性标注(Part-Of-Speech Tagging),将句子中的每一个词标注词性,比如名词.动词等:2)实体标注(Name E ...
- JS - 焦点图
下载地址:http://www.lanrentuku.com/js/jiaodiantu-1076.html 修改焦点图: CSS代码: /* 懒人图库 搜集整理 www.lanrentuku.com ...
- 理清JavaScript正则表达式
理清JavaScript正则表达式--下篇 紧接:"理清JavaScript正则表达式--上篇". 正则在String类中的应用 类String支持四种利用正则表达式的方法.分别是 ...