首页 > 代码库 > C++学习笔记2--面向对象

C++学习笔记2--面向对象

类的声明格式:
class 类名标识符
{
[public:]
[数据成员的声明]
[成员函数的声明]
[private:]
[数据成员的声明]
[成员函数的声明]
[protected:]
[数据成员的声明]
[成员函数的声明]
};

【类的实现】
第一种方法是将类的成员都定义在类体内。
第二种方法,也可以将类体内的成员函数的实现放在类体外,但如果类成员定义在类体外,需要用到域运算符“::”,放在类体内和类体外的效果是一样的。
C++语言可以实现将函数的声明和函数的定义放在不同的文件,一般在头文件放入函数的声明,在实现文件放入函数的实现。可将类的定义放在头文件中,将类成员变量放在实现文件内。
【构造函数】
类的构造方法:
class CPerson {
public:
    CPerson();
    int m_iIndex;
    int getIndex();
};
//构造函数
CPerson::CPerson() {
    m_iIndex = 10;
}


CPerson()是CPerson的默认构造方法,构造方法可以定义为带参的。
【复制构造函数】
复制构造函数就是函数的参数是一个已经初始化的类对象。
范例:
#include <iostream>
#include <cstring>
using namespace std;
class Person {
public:
    Person(int _index, char *_name); //构造函数
    Person(Person & copyPerson); //复制构造函数
    int index;
    char name[30];
};
//构造函数
Person::Person(int _index, char *_name) {
    index = _index;
    strcpy(name, _name);
}
//复制构造函数
Person::Person(Person & copyPerson) {
    index = copyPerson.index;
    strcpy(name, copyPerson.name);
}
int main(int argc, char *argv[]) {
    Person p(1, "lasolmi");
    Person q(p);
    cout << q.name << endl;
    return 0;
}


【析构函数】
构造函数主要用来在对象创建时,给对象中的一些数据成员赋值,主要目的就是来初始化对象。
析构函数的功能是用来释放一个对象的,在对象删除前,用它来做一些清理工作,它与构造函数的功能正好相反。
CPerson::~CPerson() {
    delete[] m_pMessage;
}


【类成员】
public属性的成员对外可见,对内可见。
private属性的成员对外不可见,对内可见。
protected属性的成员对外不可见,对内可见,且对派生类是可见的。
在默认情况下,类成员的属性为private。
【内联成员函数】
类内(类内默认inline)声明:inline char* GetUsername() const;
类外直接定义:inline char* CUser::GetUsername() const {...}
【静态类成员】
静态类成员在类成员定义前使用static关键字标识。例如:
class CBook {
public:
    static unsigned int m_Price;
};
在定义静态数据成员时,通常需要在类体外部对静态成员进行初始化。例如:
unsigned int CBook::m_Price = 10;
对于静态成员来说,不仅可以通过对象访问,还可以直接使用类名访问。例如:
int main(int argc,char* argv[]) {
    CBook book;
    cout << CBook::m_Price << endl; //通过类名访问静态成员
    cout << book.m_Price << endl; //通过对象访问静态成员
    return 0;
}


静态数据成员可以是当前类的类型,而其他数据成员只能是当前类的指针或引用类型。
例:
class CBook {
public:
    static unsigned int m_Price;
    CBook m_book;           //非法的定义,不允许在该类中定义所属类的对象
    static CBook m_VCbook;  //正确,静态数据成员允许定义类的所属类对象
    CBook *m_pBook;         //正确,允许定义类的所属类型的指针类型对象
}


静态数据成员可以作为成员函数的默认参数。
静态成员函数的丁一部分写在类外时无需加static。
C++类中藏有this指针。
【嵌套类】
范例:在定义CList类时,在内部定义了一个嵌套类CNode。
#include <iostream>
#include <cstring>
using namespace std;
#define MAXLEN 128
class CList {
public:
    class CNode {
        friend class CList;
    private:
        int m_Tag;
    public:
        char m_Name[MAXLEN];
    };
public:
    CNode m_Node;
    void SetNodeName(const char *pchData) {
        if(pchData != NULL) {
            strcpy(m_Node.m_Name, pchData);
        }
    }
    void SetNodeTag(int tag) {
        m_Node.m_Tag = tag;
    }
};
int main(int argc, char* argv[]) {
    CList c;
    c.SetNodeName("lasolmi");
    cout << c.m_Node.m_Name << endl;
    return 0;
}


上述代码在嵌套类CNode中定义了一个私有成员m_Tag,定义了一个公有成员m_Name,对于外围类CList来说,通常他不能访问嵌套类的私有成员,虽然嵌套类是在其内部定义的。但是,上述代码在定义CNode类时将CList类作为自己的友元类,这使得CList类能够访问CNode类的私有成员。
对于内部的嵌套类来说,只允许其在外围的类域中使用,在其他类域或者作用域中是不可见的。
可以采用下述方法调用:
CList::CNode node;
局部类:类的定义放置在函数中。
【友元】friend
友元类:
class B {
public:
    friend class A;
    ...
}

友元方法:
class B {
    friend void A::function();
    ...
};

对于由原函数来说,不仅可以是类的成员函数,还可以是一个全局函数。
class B {
    friend void function();
    ...
}
void function() {...}

【命名空间】
命名空间的定义格式为:
namespace 名称
{
    常量、变量、函数等对象的定义
}

引用空间成员的一般形式为是:
命名空间名称::成员;
例:定义命名空间
#include <iostream>
using namespace std;
namespace MyName1 { //定义命名空间
    int iValue = http://www.mamicode.com/10;>
另一种引用命名空间中成员的方法:使用using namespace语句。一般形式为:
using namespace 命名空间名称;
如果使用using namespace语句,则在引用空间中的成员时直接使用就可以。
例:定义嵌套的命名空间。
#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(int argc, char* argv[]) {
    Output::show();
    Output::MyName::Demo();
    return 0;
}

【继承】
类继承的形式如下:
class 派生类名标识符:[继承方式] 基类名标识符 {
    [访问控制修饰符:]
    [成员声明列表]
}

继承方式有3种派生类型:public,protected,private.
 public(共有型派生):共有型派生表示对于基类中的public数据成员和成员函数,在派生类中仍然是public,对于基类中的private数据成员和成员函数,在派生类中仍然是private。
 private(私有型派生):私有型派生表示对于基类中的public、protected数据成员和成员函数,在派生类中可以访问。基类中的private数据成员,在派生类中不可以访问。
 protected(保护型派生):保护型派生表示对于基类中的public、protected数据成员和成员函数,在派生类中均为protected。protected类型在派生类定义时可以访问,用派生类声明的对象不可以访问,也就是说在类体外不可以访问。protected成员可以被基类的所有派生类使用。这一性质可以沿继承树无限向下传播。
【子类隐藏父类的成员函数】
设B类是A类的派生类,A中存在方法function(),B中也存在方法function(),则B类成员b使用自身function()方法为:
b.function();
子类使用父类function()方法为:
b.A::function();
【重载运算符】
重载运算符的声明形式:
operator 类型名();
不允许重载的运算符:“.”、“*”、“::”、“?”、“:”。
例:通过重载运算符实现求和
#include <iostream>
using namespace std;
class CBook {
public:
    CBook(int iPage) {
        m_iPage = iPage;
    }
    CBook operator+(CBook b) {
        return CBook(m_iPage+b.m_iPage);
    }
    void display() {
        cout << m_iPage <<endl;
    }
protected:
    int m_iPage;
};
int main(int argc,char* argv[]) {
    CBook bk1(10);
    CBook bk2(20);
    CBook tmp(0);
    tmp = bk1 + bk2;
    tmp.display();
    return 0;
}

【多重继承】
C++支持多重继承。多重继承是指有多个基类名标识符,其声明形式如下:
class 派生类名标识符:[继承方式] 基类名标识符1,...,访问控制修饰符 基类名标识符n
{
    [访问控制修饰符:]
    [成员声明列表]
};

范例:鸟能够在天空飞翔,与能够在水里游,而水鸟既能够在天空飞翔,又能够在水里游。那么在定义水鸟类时,可以将鸟和鱼同时作为其基类。
#include <iostream>
using namespace std;
class CBird {
public:
    void FlyInSky() {
        cout << "鸟能够在天空飞翔" << endl;
    }
    void Breath() {
        cout << "鸟能够呼吸" << endl;
    }
};
class CFish {
public:
    void SwimInWater() {
        cout << "鱼能够在水里游" << endl;
    }
    void Breath() {
        cout << "鱼能够呼吸" << endl;
    }
};
class CWaterBird: public CBird, public CFish {
public:
    void Action() {
        cout << "水鸟能飞又能游" << endl;
    }
};
int main(int argc, char* argv[]) {
    CWaterBird waterbird;
    waterbird.FlyInSky();
    waterbird.SwimInWater();
    return 0;
}

当要用到Breath()方法,可以这么办:
waterbird.CFish::Breath(); //调用CFish类的Breath成员函数
waterbird.CBird::Breath(); //调用CBird类的Breath成员函er数
二义性:当派生类的两个或多个父类中都含有function函数,派生类将不知道调用哪个function成员函数,这就产生了二义性。
多重继承的构造函数被调用的顺序以类派生表中生命的顺序为准。派生表就是多重继承定义中继承方式后面的内容,调用顺序就是按照基类名标识符的前后顺序进行的。
【多态】
C++语言中,多态指:具有不同功能的函数可以用同一个函数名。
多态性通过联编实现。联编指计算机程序彼此关联的过程。
联编按进行的阶段不同分为:静态联编 和 动态联编。
C++中,按联编的时刻不同,存在两种类型多态性:函数重载 和 虚函数。
在基类中用virtual声明成员函数为虚函数。
覆盖和重载的区别是:重载是同一层次函数名相同,覆盖是在继承层次中成员函数的函数原型完全相同。
例:利用虚函数实现动态绑定
#include <iostream>
#include <cstring>
using namespace std;
class CEmployee {   //定义CEmployee类
public:
    int m_ID;
    char m_Name[128];
    char m_Depart[128];
    CEmployee() {
        memset(m_Name, 0, 128);
        memset(m_Depart, 0, 128);
    }
    virtual void OutputName() {     //定义一个虚成员函数
        cout << "员工姓名:" << m_Name << endl;
    }
};
class COperator:public CEmployee {  //从CEmployee类派生一个子类
public:
    char m_Password[128];
    void OutputName() {
        cout << "操作员姓名:" << m_Name << endl;
    }
};
int main(int argc, char* argv[]) {
    CEmployee *pWorker = new COperator(); //定义CEmployee类型指针,调用COperator类构造函数
    strcpy(pWorker->m_Name, "lasolmi");   //设置m_Name数据成员信息
    pWorker->OutputName();                //调用COperator类的OutputName成员函数
    delete pWorker;                       //释放对象
    return 0;
}

虚函数有以下几方面限制:
(1)只有类的成员函数才能为虚函数。
(2)静态成员函数不能为虚函数,因为静态成员函数不受限于某个对象。
(3)内联函数不能是虚函数,因为内联函数是不能在运行中动态确定其位置的。
(4)构造函数不能使虚函数,析构函数通常是虚函数。
从CBird类和CFish类派生子类CWaterBird类时,在CWaterBird类中将存在两个CAnimal类的复制。那么如何在派生CWaterBird类时使其只存在一个CAnimal基类呢?C++语言提供的徐继承机制,解决了这个问题。
例:虚继承
#include <iostream>
using namespace std;
class CAnimal { //定义一个动物类
public:
    CAnimal() {cout<<"动物类被构造"<<endl;}
    void move() {cout<<"动物能够移动"<<endl;}
};
class CBird : virtual public CAnimal { //从CAnimal类虚继承CBird类
public:
    CBird() {cout<<"鸟类被构造"<<endl;}
    void FlyInSky() {cout<<"鸟能够在天空飞翔"<<endl;}
    void Breath() {cout<<"鸟能够呼吸"<<endl;}
};
class CFish : virtual public CAnimal { //从CAnimal类虚继承CFish类
public:
    CFish() {cout<<"鱼类被构造"<<endl;}
    void SwimInWater() {cout<<"鱼能够在水里游"<<endl;}
    void Breath() {cout<<"与能够在水里游"<<endl;}
};
class CWaterBird : public CBird,public CFish {
public:
    CWaterBird() {cout<<"水鸟类被构造"<<endl;}
    void Action() {cout<<"水鸟既能飞又能游"<<endl;}
};
int main(int argc,char* argv[]) {
    CWaterBird waterbird;
    return 0;
}

输出结果为:
动物类被构造
鸟类被构造
鱼类被构造
水鸟类被构造
【抽象类】
包含至少一个纯虚函数的类称为抽象类。
抽象类只能作为基类用来派生出新的子类,而不能在程序中实例化(即不能说明抽象类的对象),但是可以使用指向抽象类的指针。
纯虚函数(Pure Vitual Function):指被标明为不具体实现的虚成员函数,它不具备函数功能。
虚函数不能被直接调用,仅起到提供一个与派生类相一致的接口的作用。
声明虚函数的形式为:
virtual 类型 函数名(参数表列)=0;
实现抽象类中的成员函数:抽象类通常用于作为其他类的父类,从抽象类派生的子类如果是抽象类,则子类必须实现父类中的所有纯虚函数。
例:实现抽象类中的成员函数
#include <iostream>
#include <cstring>
using namespace std;
class CEmployee { //定义CEmployee类
public:
    int m_ID;
    char m_Name[128];
    char m_Depart[128];
    virtual void OutputName()=0; //定义抽象成员函数
};
class COperator : public CEmployee {
public:
    char m_Password[128];
    void OutputName() {cout<<"操作员姓名:"<<m_Name<<endl;}
    COperator() {strcpy(m_Name, "lasolmi");}
};
class CSystemManager : public CEmployee { //定义CSystemManager类
public:
    char m_Password[128];
    void OutputName() {cout<<"系统管理员姓名:"<<m_Name<<endl;}
    CSystemManager() {strcpy(m_Name, "congli");}
};
int main(int argc, char* argv[]) {
    CEmployee *pWorker;         //定义CEmployee类型指针
    pWorker = new COperator();  //调用COperator类的构造函数,为pWorker赋值
    pWorker->OutputName();      //调用COperator类的OutputName成员函数
    delete pWorker;             //释放pWorker对象
    pWorker = NULL;             //将pWorker对象设置为空
    pWorker = new CSystemManager();  //调CSystemManager用类的构造函数,为pWorker赋值
    pWorker->OutputName();      //调用CSystenManager类的OutputName成员函数
    delete pWorker;             //释放pWorker对象
    pWorker = NULL;             //将pWorker对象设置为空
    return 0;
}


C++学习笔记2--面向对象