IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++面向对象的程序设计(OOP) -> 正文阅读

[C++知识库]C++面向对象的程序设计(OOP)

Class的两个分类

  • class without pointer merber(s)
    complex
  • class with pointer merber(s)
    string

1 c/c++关于数据和函数

还在路上,稍等... 还在路上,稍等...

基于对象:面对的是单一的class的设计
面向对象:面对的是多重classes的设计,classes和classes之间的关系

2 c++程序代码基本形式

还在路上,稍等...

延伸文件名不一定是.h.cpp,也可能是其他甚至没有。

2.1 主程序

#include <iostream>
#include "complex.h"
using namespace std;

int main()
{
	return 0;
}

2.2 头文件中的防卫式声明

complex.h

#ifndef __COMPLEX__
#define __COMPLEX__
...
#endif

3 complex (without pointer)

3.1头文件布局

#ifndef __COMPLEX__
#define __COMPLEX__
#include<cmath>

/***********forward declarations(前置声明)********/
class ostream;
class complex;

complex&
    __doapl (complex* ths, const complex& r);

/*********class declarations(类-声明)**********/
class complex
{
    ...
};

/**********class definiton(类-定义)**********/
complex::function ...

#endif

3.2 class的声明

class complex     //class head
{                 //class body
public:
    complex (double r = 0, double i = 0)
    : re (r), im(i)
    {}
    complex& operator += (const complex&); //只是一个声明
    double real () const {return re;}      //直接在这里定义
    double imag () const {reutn im;}       //有些函数在此直接定义,另一些在body之外定义
private:
    double re, im;

    friend complex& __doapl (complex*, const complex&);
};
//使用方法
{
    complex c1(2,1);
    complex c2;
    ...
}

3.3 类template(模板)简介

template<typename T>
class complex
{
public:
    complex (T r = 0, T i = 0)
    : re (r), im(i)
    {}
    complex& operator += (const complex&);
    T real () const {return re;}
    T imag () const {reutn im;}
private:
    T re, im;

    friend complex& __doapl (complex*, const complex&);
};
//使用时指定T的类型
{
    complex<double> c1(2.5,1.5);   //T绑定为double
    complex<int> c2(2,6);
    ...
}

3.4 inline(内联)函数

如果函数在class body内定义,自动成为inline候选,如果在class本体外定义就不是inline。
inline只是对编译器的建议,由编译器决定,如果函数太复杂,编译器就没有能力把函数变成inline。

inline double        //如果在body外定义,可以在前面加上inline 
imag(const complex& x)
{
    return x.imag ();
}

3.5 访问级别

public:公开的外界能看得到 函数
private:只有class自己能看得到 数据封装起来,不希望随便调用

//见 3.2 class声明
{
    complex c1(2,1);
    cout << c1.re;   //错误。数据在private,外部不能直接访问
    cout << c1.im;
}
{
    complex c1(2,1);
    cout << c1.real();  //正确。函数在public,可以调用成员函数来访问数据
    cout << c1.imag();
}

3.6 构造函数

如果想要创建一个对象构造函数会被自动调用。

  • 构造函数一定要跟类的名字相同
  • 它可以拥有参数
  • 参数可以有默认值 //如果创建的时候没有指明参数,则使用默认值 其它函数也可以有默认值
  • 没有返回类型 //
class complex     
{                 
public:
    complex (double r = 0, double i = 0)   //默认实参
    : re (r), im(i)   //初值列,只有构造函数有的语法 
    {}
    complex& operator += (const complex&); 
    double real () const {return re;}      
    double imag () const {reutn im;}       
private:
    double re, im;
    friend complex& __doapl (complex*, const complex&);
};

一个变量数值的设定有两个阶段:初始化、赋值

complex (double r = 0, double i = 0)
{  re = r; im = i;  }         //赋值   效果等同于初始化,但是效率低

构造函数对应析构函数,不带指针的类多半不用写析构函数

3.7 overloading(重载)

同名函数可以有很多个(实际不相同)——重载

  • 函数重载常常发生在构造函数里
  • 如果构造函数有默认值,不能重载为无默认值的函数
// 构造函数、real函数重载比较
class complex
{
public:
    complex (double r = 0, double i = 0)   //有默认值,当创建对象没有给参数时可以被调用
    : re (r), im(i)
    { }
    complex () : re(0), im(0) { }  //重载不正确,没有给参数时两个构造函数都可以被调用
    complex& operator += (const complex&);
    double real () const {return re;}
    double imag () const {reutn im;}
private:
    double re, im;

    friend complex& __doapl (complex*, const complex&);
};


void real(double r) { re = r; }   //重载正确
?real@Complex@@QBENXZ     
?real@Complex@@QAENABN@Z   //两个real名称相同,但编译后的实际名称不同(参数不同)

3.8 Singleton(单例)设计模式

把构造函数放在private,只允许外界创建一个例子

class A
{
public:
    static A& getInstance();
    setup() {...}
private:
    A();
    A(const A& rhs);
    ...
};

A& A::getInstance()
{
    static A a;
    return a;
}

A::getInstance().setup();   //通过调用这个函数创建对象

3.9 const成员函数

对class里面的函数分为会改变数据不会改变数据两种,不会改变数据内容的加上const

 class complex
{
public:
    complex (double r = 0, double i = 0)   
    : re (r), im(i)
    { }
    complex& operator += (const complex&);    
    double real () const {return re;}
    double imag () const {reutn im;}
private:
    double re, im;

    friend complex& __doapl (complex*, const complex&);
};
//如果该加而没加const
{    //正确
    complex c1(2,1);     
    cout << c1.real();
    cout << c1.imag();
}
{    //错误
    const complex c1(2,1);  //对象前面加const,对象的内容不能改 
    cout << c1.real();      //real有可能改变对象的数据 ,编译不通过 
    cout << c2.imag();
}

3.10 参数传递、返回值传递

3.10.1 参数传递:pass by value / pass by reference(to const)

  • pass value:整个数据传过去,有多少传多少
  • 引用底部就是一个指针,传引用相当于传指针那么快
  • 最好所有参数传递都传引用
  • 引用有指针的效果,当不希望改数据时加const
class complex
{
public:
    complex (double r = 0, double i = 0)   //pass by value
    : re (r), im(i)
    { }
    complex& operator += (const complex&); //pass by reference to const
    double real () const {return re;}
    double imag () const {reutn im;}
private:
    double re, im;

    friend complex& __doapl (complex*, const complex&);
};
{
    complex c1(2,1);   //by value
    complex c2;
    c2 += c1;  //by reference 
    cout << c2;
}
ostream&
operator << (ostream& os, const complex& x)   //os   pass by reference
{
    return os << '(' << real (x) << ','
              << imag (x) << ')';
}

3.10.2 返回值传递:return by value / return by reference(to const)

complex& operator += (const complex&);    // return by reference 类型时complex
double real () const {return re;}   // return by value 类型时double

不能返回局部变量的引用,除此之外都能return by reference,尽量传refernece
传递者无需知道接收者是以reference形式接收 3.12.1

inline complex&
__doapl (complex* ths, const complex& r)
{
    ths->re += r.re;     //第一参数会被改变
    ths->im += r.im;     //第二参数不会被改变
    return *ths;      //this本来就存在,可以传引用
}

inline complex&
complex::operator += (const complex& r)
{
    return __doapl (this, r);
}

3.11 friend(友元)

friend complex& __doapl (complex*, const complex&);
inline complex&
__doapl (complex* ths, const complex& r)
{
    this->re += r.re;
    this->im += r.im;//自由取得friend的private成员
    return *ths;
}
  • 外部想要取数据通过public函数实现,友元friend可以直接拿private的数据。
  • 友元效率更快,但是打破了封装。

相同class的各个objects互为friends

class complex
{
public:
    complex (double r = 0; double i = 0)
    : re (r), im (i)
    { }

    int func(const complex& param)    
    { return param.re + param.im; }

private:
    double re, im;
};
{
    complex c1(2,1);
    complex c2;

    c2.func(c1);    //c2直接取c1的数据
}

3.12 操作符重载

3.12.1 操作符重载-1,成员函数(this)

传递者无需知道接收者是以reference形式接收

inline complex&    //声明return by reference    
__doapl(complex* ths, const complex& r)
{
	ths->re += r.re;
	ths->im += r.im;
	return *ths;	 //返回的是一个对象value,不必管以什么形式接收
}

inline complex&   //c3+=c2+=c1 返回类型不能是void
complex::operator += (const complex& r) //这里有一个参数this,不能在参数列 写出来,但在函数内能使用
{
	return __doapl (this,r);
}

{
	complex c1(2,1);
	complex c2(5);
	c2 += c1;   //+=操作符重载
}

3.12.2 操作符重载-2,非成员函数(无this)

在class的body之外,带有class名称的是成员函数,不带class名称的是全域函数

{
    complex c1(2,1);

    cout << imag(c1);
    cout << real(c1);
}
//为了应对三种可能的用法,这里有三个函数
inline complex    //返回的是value,不是引用     
operator + (const complex& x,const complex& y)
{
	return complex(real (x) + real (y),    //临时对象
	               imag (x) + imag (y));
}

inline complex
operator + (const complex& x,double y)
{
	return complex(real (x) + y, imag (x));
}

inline complex
operator + (double x,const complex& y)
{
	return complex(x + real (y), imag (y));
}

这三个函数不带class名称,是全域函数。不能return by reference,因为他们返回的必定是local object

临时对象

typrname();

<<操作符重载只能是全域函数,

ostream&   //返回值类型不能是void
operator << (ostream& os, const complex& x)   //os的状态会改变,不能加const
{
	return os << '('<< real (x) << ','<< imag (x) << ')';
}
{
	cout << c1 << conj(c1); //c1输出到cout的结果还要能接收conj(c1),因此操作符重载返回值不能为void
}

3.13 class之外的各种定义

  • 构造函数尽量用初值列
  • 数据放在private
  • 参数尽可能以reference传递,要不要加const
  • 返回值尽量以reference传
  • 类的body里的函数应该加const就要加

4 string (with pointer)

标准库类型String表示可变长的字符序列
字符直接量用单引号'',字符串直接两用双引号""
字符串里面只有一个指针

定义和初始化String对象

string s1;            // 空字符串
string s2(s1);        // s2是s1的副本
string s2 = s1;         // 等价于s2(s1)
string s3("value")// s3是字面值"value"的副本,除了字面值最后的那个空字符
string s3 = "value"//等价于 s3("value"),s3是字面值"value"的副本
string s4(n,'c');     //把s4初始化为由连续n个字符c组成的串

如果使用等号初始化一个变量,执行的是拷贝初始化,编译器把等号右侧的初始值拷贝到新创建的对象中去。如果不适用等号,则执行的是直接初始化

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-19 07:48:45  更:2021-09-19 07:50:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 21:21:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码