寒假C++学习4-面向对象编程基础,类和对象(好多啊qwq)

目录

一.面向对象概述(OO)

面向对象技术的基本思想

抽象

封装

面向对象的特点:

统一建模语言(UML)

1)概述

2)统一建模语言的结构

二.类和对象

1.C++类

·类的声明和定义

·类的实现-两种方式

·对象的声明和引用-和结构体一样

2.构造函数

1)初始化

2)复制构造函数-用一个已经初始化的对象来生成一个一模一样的对象

3.析构函数

4.类成员

1)public,private,protected 访问控制权限

2)内联成员函数

3)静态类成员

4)静态成员函数

5)隐藏的this指针

6)嵌套类

7)局部类

5.友元-friend

6.命名空间

1)定义命名空间

2)在程序中引入命名空间

3)在多个文件中定义命名空间-编程规范

4)定义嵌套的命名空间

5)定义未命名的命名空间


一.面向对象概述(OO)

1.)面向对象:设计思想

2)特点:抽象,封装,继承,多态

3)面向对象与面向过程编程

面向过程编程的缺点:1.软件重用性差。2.软件可维护性差。3.开发出的软件不能满足用户需要

面向对象技术的基本思想

1.客观世界是由对象组成

2.具有相同数据和相同操作的对象可以归并为一个类,对象是对象类的一个实例

3.类可以派生出子类,子类继承父类的全部特性(数据和操作),又可以有自己的新特性,子类和父类形成类的层次结构

抽象

抽象的过程是将有关事物的共性归纳,集中的过程

封装

封装是面向编程的核心思想,将对象的属性和行为封装起来,而将对象的属性和行为封装起来的载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想

面向对象的特点:

1.代码容易修改

2.代码复用性高

统一建模语言(UML)

1)概述

UML是统一建模语言的英文缩写,它是一种直观化,明确化,构建和文档化软件系统产物通用可视化建模语言

UML记录了被构建系统有关理解和决定,可用于对系统的理解,设计,浏览,配置以及信息控制

UML的应用贯穿在系统开发的需求分析,分析,设计,构造,测试五个阶段。它包括概念的语义,表示法和说明,提供静态,动态,系统环境以及组织结构的建模。

2)统一建模语言的结构

UML有图和元模型共同组成,其中图是UML的语法,而元模型则是给出图的意思,它是UML的语义。

UML的语义定义在一个4层抽象级建模概念框架中,这4层结构分别是:

1.元介质模型层

该层描述基本的类型,属性,关系,这些元素都用于定义UML元模型。元介质模型强调用少数功能较强的模型成分来组合表达复杂的语义。每个方法和技术都应在相对独立的抽象层次上

2.元模型层

该层组成了UML的基本元素,包括面向对象和面向组件的概念,这一层的每个概念都在元介质模型的“事物”的实例中

3.模型层

该层组成了UML的模型,这一层中的每个概念都是在元模型层中概念的一个实例,这一层的模型通常叫作类模型或类型模型

4.用户模型层

UML使用模型来描述系统的结构或者静态特征,以及行为或动态特征,它通过不同的视图来体现行为或动态特征。

常用的视图:

1.用例视图

2.逻辑视图

3.并发视图

4.组件视图

5.开发视图

这都是啥?qwq,唉,tcl


二.类和对象

1.C++类

类本身和java一样,就不记录下来了。

·类的声明和定义

class 类名标识符{ //类名 //{}为类体,类空间
public:
    [数据成员的声明]
    [数据函数的声明]
private:
    [数据成员的声明]
    [数据函数的声明]
protected:
    [数据成员的声明]
    [数据函数的声明]
};

举个例子:

class Person{
    /*数据成员*/
    int Age;
    char Name[25];
    double Salary;
    /*成员函数*/
    int getAge(int sAge);
    int setSalary(double dSalary);
};

·类的实现-两种方式

1.类的成员函数都定义在类体内

class CPerson{
public:
    //数据成员
    int m_iIndex;
    char m_cName[25];
    short m_shAge;
    double m_dSalary;
    //成员函数
    short getAge();
    int setAge(short sAge);
    int getIndex() ;
    int setIndex(int iIndex);
    char* getName() ;
    int setName(char cName[25]);
    double getSalary() ;
    int setSalary(double dSalary);
};

2.将类体内的成员函数的实现放在类体外,此时需要用到域运算符"::",放在类体内和类体外的效果是一样的

#include<bits/stdc++.h>

class CPerson{
public:
    //数据成员
    int m_iIndex;
    char m_cName[25];
    short m_shAge;
    double m_dSalary;
    //成员函数
    short getAge();
    int setAge(short sAge);
    int getIndex() ;
    int setIndex(int iIndex);
    char* getName() ;
    int setName(char cName[25]);
    double getSalary() ;
    int setSalary(double dSalary);
};
//类成员函数的实现部分
short CPerson::getAge() {
    return m_shAge;
}
int CPerson::setAge(short sAge) {
    m_shAge=sAge;
    return 0;                                //执行成功返回0
}
int CPerson::getIndex() {
    return m_iIndex;
}
int CPerson::setIndex(int iIndex) {
    m_iIndex=iIndex;
    return 0;//执行成功返回0
}
char* CPerson::getName() {
    return m_cName;
}
int CPerson::setName(char cName[25]) {
    strcpy(m_cName,cName);
    return 0;//执行成功返回0
}
double CPerson::getSalary() {
    return m_dSalary;
}
int CPerson::setSalary(double dSalary) {
    m_dSalary=dSalary;
    return 0;//执行成功返回0
}

注意:一般再头文件放入函数的声明,在实现文件内放入函数的实现文件。同样可以将类的定义放在头文件中,将类成员函数的实现放在实现文件内。例如:

person.h

class CPerson{
public:
    //数据成员
    int m_iIndex;
    char m_cName[25];
    short m_shAge;
    double m_dSalary;
    //成员函数
    short getAge();
    int setAge(short sAge);
    int getIndex() ;
    int setIndex(int iIndex);
    char* getName() ;
    int setName(char cName[25]);
    double getSalary() ;
    int setSalary(double dSalary);
};

person.cpp

#include "Person.h"
#include <stdlib.h>
#include <string.h>

short CPerson::getAge() {
    return m_shAge;
}
int CPerson::setAge(short sAge) {
    m_shAge=sAge;
    return 0;                                //执行成功返回0
}
int CPerson::getIndex() {
    return m_iIndex;
}
int CPerson::setIndex(int iIndex) {
    m_iIndex=iIndex;
    return 0;//执行成功返回0
}
char* CPerson::getName() {
    return m_cName;
}
int CPerson::setName(char cName[25]) {
    strcpy(m_cName,cName);
    return 0;//执行成功返回0
}
double CPerson::getSalary() {
    return m_dSalary;
}
int CPerson::setSalary(double dSalary) {
    m_dSalary=dSalary;
    return 0;//执行成功返回0
}

·对象的声明和引用-和结构体一样

#include <iostream.h>
#include "Person.h"
int main() {
    int iResult=-1;
    CPerson p;
    iResult=p.setAge(25);
    if(iResult>=0)
        cout << "m_shAge is:" << p.getAge() << endl;

    iResult=p.setIndex(0);
    if(iResult>=0)
        cout << "m_iIndex is:" << p.getIndex() << endl;

    char bufTemp[]="Mary";
    iResult=p.setName(bufTemp);
    if(iResult>=0)
        cout << "m_cName is:" << p.getName() << endl;

    iResult=p.setSalary(1700.25);
    if(iResult>=0)
        cout << "m_dSalary is:" << p.getSalary() << endl;
    return 0;
}

2.构造函数

1)初始化

类的初始化和结构体不同,不能像结构体一样直接赋值。

class node{
public:
    int a;
    double b;
    char c;
    void f();
};
//构造函数
node::node(){
    a = 1;
    b = 3.14;
    c = 'a';
}

很简单,举个例子(当作复习了):

#include <iostream>
using namespace std;
//定义CPerson类
class CPerson {
public:
    CPerson();
    CPerson(int iIndex,short m_shAge,double m_dSalary);
    int m_iIndex;
    short m_shAge;
    double m_dSalary;
    int getIndex();
    short getAge();
    double getSalary();
};
//在默认构造函数中初始化
CPerson::CPerson() {
    m_iIndex=0;
    m_shAge=10;
    m_dSalary=1000;
}
//在带参数的构造函数中初始化
CPerson::CPerson(int iIndex,short m_shAge,double m_dSalary) {
    m_iIndex=iIndex;
    m_shAge=m_shAge;
    m_dSalary=m_dSalary;
}
int CPerson::getIndex() {
    return m_iIndex;
}
//在main函数中输出类的成员值
int main() {
    CPerson p1;
    cout << "m_iIndex is:" << p1.getIndex() << endl;

    CPerson p2(1,20,1000);
    cout << "m_iIndex is:" << p2.getIndex() << endl;
    return 0;
}
//m_iIndex is:0
//m_iIndex is:1

2)复制构造函数-用一个已经初始化的对象来生成一个一模一样的对象

复制构造函数时编译器调用来完成一些基于同一类的其他对象的构建及初始化,其唯一形参必须是引用

举个例子:

Person.cpp

class CPerson
{
public:
    CPerson(int iIndex,short shAge,double dSalary);//构造函数
    CPerson(CPerson & copyPerson);//复制构造函数
    int m_iIndex;
    short m_shAge;
    double m_dSalary;
    int getIndex();
    short getAge();
    double getSalary() ;
};
//构造函数
CPerson::CPerson(int iIndex,short shAge,double dSalary)
{
    m_iIndex=iIndex;
    m_shAge=shAge;
    m_dSalary=dSalary;
}
//复制构造函数
CPerson::CPerson(CPerson & copyPerson)
{
    m_iIndex=copyPerson.m_iIndex;
    m_shAge=copyPerson.m_shAge;
    m_dSalary=copyPerson.m_dSalary;
}
short CPerson::getAge()
{
    return m_shAge;
}
int CPerson::getIndex()
{
    return m_iIndex;
}
double CPerson::getSalary()
{
    return m_dSalary;
}

Person.cpp

#include "Person.h"
#include <stdlib.h>
#include <string.h>

short CPerson::getAge()
{
    return m_shAge;
}
int CPerson::setAge(short sAge)
{
    m_shAge=sAge;
    return 0;                                //执行成功返回0
}
int CPerson::getIndex()
{
    return m_iIndex;
}
int CPerson::setIndex(int iIndex)
{
    m_iIndex=iIndex;
    return 0;//执行成功返回0
}
char* CPerson::getName()
{
    return m_cName;
}
int CPerson::setName(char cName[25])
{
    strcpy(m_cName,cName);
    return 0;//执行成功返回0
}
double CPerson::getSalary()
{
    return m_dSalary;
}
int CPerson::setSalary(double dSalary)
{
    m_dSalary=dSalary;
    return 0;//执行成功返回0
}

main.cpp

#include <iostream>
#include "Person.h"
using namespace std;
int main(){
    CPerson p1(20,30,100);
    CPerson p2(p1);
    cout << "m_iIndex of p1 is:" << p2.getIndex() << endl;
    cout << "m_shAge of p1 is:" << p2.getAge() << endl;
    cout << "m_dSalary of p1 is:" << p2.getSalary() << endl;
    cout << "m_iIndex of p2 is:" << p2.getIndex() << endl;
    cout << "m_shAge of p2 is:" << p2.getAge() << endl;
    cout << "m_dSalary of p2 is:" << p2.getSalary() << endl;
    return 0;
}
//m_iIndex of p1 is:20
//m_shAge of p1 is:30
//m_dSalary of p1 is:100
//m_iIndex of p2 is:20
//m_shAge of p2 is:30
//m_dSalary of p2 is:100

3.析构函数

析构函数的功能就是在对象删除之前做一些清理的工作。与构造函数正好相反。加一个~即可:

Person.h

#include <iostream>
#include <string.h>
using namespace std;
class CPerson {
public:
    CPerson();
    ~CPerson();//Îö¹¹º¯Êý
    char* m_pMessage;
    void ShowStartMessage();
    void ShowFrameMessage();
};
CPerson::CPerson() {
    m_pMessage = new char[2048];
}
void CPerson::ShowStartMessage() {
    strcpy(m_pMessage,"Welcome to MR");
    cout << m_pMessage << endl;
}
void CPerson::ShowFrameMessage() {
    strcpy(m_pMessage,"**************");
    cout << m_pMessage << endl;
}
CPerson::~CPerson() {
    delete[] m_pMessage;
}

Person.cpp

#include "Person.h"
#include <stdlib.h>
#include <string.h>

short CPerson::getAge() {
    return m_shAge;
}
int CPerson::setAge(short sAge) {
    m_shAge=sAge;
    return 0;                                //执行成功返回0
}
int CPerson::getIndex() {
    return m_iIndex;
}
int CPerson::setIndex(int iIndex) {
    m_iIndex=iIndex;
    return 0;//执行成功返回0
}
char* CPerson::getName() {
    return m_cName;
}
int CPerson::setName(char cName[25]) {
    strcpy(m_cName,cName);
    return 0;//执行成功返回0
}
double CPerson::getSalary() {
    return m_dSalary;
}
int CPerson::setSalary(double dSalary) {
    m_dSalary=dSalary;
    return 0;//执行成功返回0
}

main.cpp

#include <iostream>
using namespace std;
#include "Person.h"
int main(){
    CPerson p;
    p.ShowFrameMessage();
    p.ShowStartMessage();
    p.ShowFrameMessage();
    return 0;
}

注意:

1.一个类中只能定义一个析构函数

2.析构函数不能重载

3.构造函数和析构函数不能使用return语句返回值,不用加上关键词void

构造函数与析构函数的调用环境:

1.自动变量的作用域是某个模块,当此模块被激活时,自动变量调用构造函数,当退出此模块时,会调用析构函数

2.全局变量在进入main()函数之前会调用构造函数,在程序终止时会调用析构函数

3.动态分配的对象在使用new为对象分配内存时会调用构造函数;使用delete删除对象时会调用析构函数

4.临时变量时为了支持计算由编译器自动产生的,临时变量的生存期的开始和结尾会调用构造函数和析构函数

4.类成员

1)public,private,protected 访问控制权限

可见性和java类似,protected对外不可见,对内可见,且对派生类是可见的

注意:如果在类定义的时候没有加任何关键字,默认状态类成员都在private区域

2)内联成员函数

在定义成员函数的时候也可以使用inline,其实,对于成员函数,即使没有inline关键字,该成员函数也被认为是内联成员函数。内联成员函数可能导致潜在的代码膨胀。

举个例子:

class CUser{
private:
    char Username[128];
    char Password[128];
public:
    inline char* GetUsername()const;
};

char* CUser::GetUsername()const{
    return (char* )Username;
}

补充:对于const放在函数前后:

int GetY() const;      该函数为只读函数,不允许修改其中的数据成员的值。

const int * GetPosition();      修饰的是返回值,表示返回的是指针所指向值是常量。

3)静态类成员

之前所有的类成员都是必须通过对象来访问的,不能通过类名来访问。而静态类成员,能够通过类名直接对其访问,并且在定义时通常要在类体外对其初始化

#include<bits/stdc++.h>
using namespace std;

class node{
public:
    node();
    static int a;
};

int node::a = 6;

node::node(){
    a = 9;
}

int main(){
    cout << node::a << endl;
    node test;
    cout << test.a << endl;

    return 0;
}
//6
//9

静态类成员是被所有类对象所共享的。

注意:

1.静态数据成员可以是当前类的类型,而其他数据成员只能是当前类的指针或应用类型

class node{
public:
    static int a;
    node n1;//非法的定义,不允许在该类中定义所属类的对象
    node *n2;//合法的定义,允许定义类的所属类型的指针类型对象
    static node n3;//合法的定义,静态数据成员允许定义类的所属类对象
};

2.静态数据成员可以作为成员函数的默认参数

class CBook{
public:
    static int m_price;
    int m_pages;
    void OutputInfo(int data = m_price){
        cout << data << endl;
    }
    void OutputPage(int page = m_pages){//错误的定义,类的普通成员不能作为默认参数
        cout << page << endl;
    }
};

4)静态成员函数

1.类的静态成员函数只能访问类的静态数据成员,而不能访问普通的数据成员

2.静态成员函数不能定义成const成员函数

static void OutputInfo()const;//错误的定义

3.在类体外实现时不能加static

5)隐藏的this指针

对于类的非静态成员,每个对象都是类的一份复制,成员函数对于每个对象是共享的,那么调用共享的成员函数的时候如何找到自己的数据成员呢?隐藏的this指针。

void f1(){
    cout << this->page << endl;
}

void f1(CBook *this){
    cout << this->page << endl;
}

void f2(int page){
    this->page = page;
}

6)嵌套类

C++允许一个类中嵌套一个类,但是注意:

#include<bits/stdc++.h>
using namespace std;

class A{
public:
    int len;
    class a{
    //friend class A;
    private:
        double tag;
    };
};

int main(){
    a test;//error!内部嵌套的类main()函数是不可见,只有A可见
    A::a test//ok!通过外围类域作为限定符来定义是合法的


    return 0;
}

1.对于外围的A来说,虽然嵌套类a是在其内部定义的,但是不能够访问嵌套类的私有成员(当a类将A类作为自己的友元类时才可以访问)

2.对于内部嵌套类来说,只允许其在外围的类域中使用,在其他类域或者作用域中时不可见的,例如main()函数

7)局部类

将类定义放置在函数中,这样的类称为局部类,对于局部类,在函数之外时不能被访问

void f(){
    class CBook{
    private:
        int m_Page;
    public:
        void SetPage(int page){
            if(m_Page != page)
                m_Page = page;
        }
        int GetPage(){
            return m_Page;
        }
    };
    CBook book;
    book.SetPage(300);
    cout << book.GetPage() << endl;
}

5.友元-friend

为了保证数据的私有行的同时,对某型函数或者类不加以限制,C++采用友元提高效率。

可以在类或者函数前面加friend:

#include <bits/stdc++.h>
using namespace std;

class CItem;                                //前导声明CItem类
class CList {                              //定义CList类
private:
    CItem * m_pItem;                        //定义私有数据成员m_pItem
public:
    CList();                                //定义默认构造函数
    ~CList();                                //定义析构函数
    void OutputItem();                        //定义OutputItem成员函数
};
class CItem {                              //定义CItem类
    friend void CList::OutputItem();                //声明友元函数
private:
    char m_Name[128];                        //定义私有数据成员
    void OutputName() {                      //定义私有成员函数
        cout<< m_Name << endl;               //输出数据成员信息
    }
public:
    void SetItemName(const char* pchData) {      //定义共有方法
        if (pchData != NULL) {                  //判断指针是否为空
            strcpy(m_Name,pchData);        //赋值字符串
        }
    }
    CItem() {                              //构造函数
        memset(m_Name,0,128);                //初始化数据成员m_Name
    }
};
void CList::OutputItem() {                      //CList类的OutputItem成员函数的实现
    m_pItem->SetItemName("BeiJing");            //调用CItem类的共有方法
    m_pItem->OutputName();                //在友元函数中访问CItem类的私有方法OutputName
}
CList::CList() {                              //CList类的默认构造函数
    m_pItem = new CItem();                    //构造m_pItem对象
}
CList::~CList() {                              //CList类的析构函数
    delete m_pItem;                        //释放m_pItem对象
    m_pItem = NULL;                        //将m_pItem对象设置为空
}
int main(int argc, char* argv[]) {                  //主函数
    CList list;                                //定义CList对象list
    list.OutputItem();                        //调用CList的OutputItem方法
    return 0;
}
//BeiJing

6.命名空间

用途:在一个应用程序中的多个文件中可能存在同名的全局对象,这样会导致应用程序的链接错误,使用命名空间是消除命名冲突的最佳方式

1)定义命名空间

namespace 名称{
    常量,变量,函数等对象的定义
}

·举个例子就完事了:

#include<iostream>
using namespace std;

namespace MyName1 {                      //定义命名空间
int iValue=10;
};

namespace MyName2 {                      //定义命名空间
int iValue=20;
};

int iValue=30;                                //全局变量

int main() {
    cout<<MyName1::iValue<<endl;            //引用MyName1命名空间中的变量
    cout<<MyName2::iValue<<endl;            //引用MyName2命名空间中的变量
    cout<<iValue<<endl;
    return 0;
}
//10
//20
//30

2)在程序中引入命名空间

#include<iostream>

namespace MyName {                      //定义命名空间
    int iValue=10;                            //定义整型变量
}

using namespace std;                        //使用命名空间std
using namespace MyName;                    //使用命名空间MyName

int main() {
    cout<<iValue<<endl;                        //输出命名空间中的变量
    return 0;
}
//10

3)在多个文件中定义命名空间-编程规范

.在定义命名空间时,通常在头文件中声明命名空间中的函数,在源文件中定义命名空间中的函数,将程序的声明与实现分开

注意:在源文件中定义函数时,注意要使用命名空间作为前缀,表明实现的是命名空间中定义的函数,否则将是定义一个全局函数

将命名空间的定义放在头文件中,而将命名空间中有关成员的定义放在源文件中,符合编程规范,便于修改和观察

4)定义嵌套的命名空间

namespace Output{
    void show(){
        cout << "ok" << endl;
    }
    namespace MyName{
        void Demo(){
            cout << "myok" << endl;
        }
    }
}
//调用Demo的方法
Output::MyName::Demo();

using namespace Output::MyName;
Demo();
show();//非法,using仅仅引入了MyName命名空间,并没有引入Output命名空间,因此不能访问Output命名空间中的函数

举个例子:

#include<iostream>
using namespace std;

namespace Output {                          //定义命名空间
    void Show() {                          //定义函数
        cout<<"Output's function!"<<endl;
    }
    namespace MyName {                  //定义嵌套命名空间
        void Demo() {                      //定义函数
            cout<<"MyName's function!"<<endl;
        }
    }
}

int main() {
    Output::Show();                        //调用Output命名空间中的函数
    Output::MyName::Demo();                //调用MyName命名空间中的函数
    return 0;
}
//Output's function!
//MyName's function!

5)定义未命名的命名空间

未命名的命名空间C++支持,但是因为无命名的空间中定义的标识符被设置为全局命名空间,这样违背了命名空间设置的原则,因此没有被广泛使用

namespace{
    int a = 1;
    int b = 2;
}

终于结束了,这章好多啊qwq,累死~

猜你喜欢

转载自blog.csdn.net/guifei0/article/details/86658479
今日推荐