C++个人笔记整理

多态

一段程序能够处理多种类型对象的能力。

  • 4种形式:
  1. 强制多态:将一种类型的数据转换成另一种类型的数据。(数据类型转换,显示/隐式)
  2. 重载多态:形参类型不同,形参个数不同
  3. 包含多态:虚函数
  4. 类型参数化多态:模板

包含多态和类型参数化多态属于一般的多态性,是真正的多态性。

内联成员函数

隐式声明:将函数体直接放在类体内

class Clock{
public:
    void showTime(){
        cout<<hour<<":"<<minute<<endl;
    }
private:
    int hour,minute;
};

显式声明:函数体在类体外,函数返回值前加inline

class Clock{
public:
    void showTime();
private:
    int hour,minute;
};

inline void::Clock showTime(){
    cout<<hour<<":"<<minute<<endl;
}

复制构造函数

  • 使用一个已经存在的对象,去初始化同类的一个新对象。
  • 形参是本类的对象的引用。
  • 可根据需要定义特定的复制构造函数,若无定义,系统会在必要时自动生成一个隐含的复制构造函数。
  • 隐含的复制构造函数把初始对象的每个数据成员的值复制到新建立的对象中。
class Point{
public:
    Point(int xx=0,int yy=0){//内联构造函数
        x=xx;
        y=yy;
    }
    Point(Point &p);
private:
    int x,y;
};

Point::Point(Point &p){
    x=p.x;
    y=p.y;
}

复制构造函数被调用的3种情况:

  1. 用类的一个对象初始化该类的另一个对象。
Point a(1,2);
Point b(a);//调用
Point c=a;//调用
  1. 函数的形参是类的对象。
void f(Point p){
    ...
}

int main(){
    Point a(1,2);
    f(a);
    return 0;
}
  1. 函数的返回值是类的对象,函数返回时调用。
Point p(){
    Point a(1,2);
    return a;
}

联合体

联合体变量中的成员同时至多只有一个有意义。

类的友元

  • 友元关系:提供了不同类或对象的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。
  • 友元函数:非本类的成员函数(可为普通函数,也可为其它类的成员函数)。
    在其函数体中可通过对象名访问类的私有和保护成员。
  • 友元类
    A是B的友元类:
    A的所有成员函数都是B的友元函数,即,A的所有成员函数都可访问B的私有和保护成员。

  • 1.友元关系不能传递
    2.友元关系是单向的
    3.友元关系不被继承

常对象

数据成员值在对象的整个生存期间内不能改变。
常对象必须进行初始化,而且不能被更新。

class Point{
public:
    Point(int i,int j):x(i),y(j);
    ...
private:
    int x,y;
};

const A a(3,4);//a是常对象

const修饰的类成员

  • 常成员函数
    常成员函数不能更新目的对象的数据成员,也不能针对目的对象调用该类中没有const修饰的成员函数。
  • 常引用
    常引用所引用的对象不能被更新。如果用常引用作形参,便不会意外地发生对实参的更改。

指针

指针变量用于存放内存单元地址。
“ * ”:指针运算符,获取指针指向变量的值。
“ & ”:取地址运算符,得到一个对象的地址。

派生类

  • 构造函数
    构造派生类的对象时,首先调用基类构造函数初始化它们的数据成员,然后按照构造函数初始化列表中指定的方式初始化派生类新增的成员对象,最后才执行派生类构造函数的函数体。
  • 多继承
    (1)多个基类、派生类有同名成员,对象名.成员名对象指针->成员名访问派生类成员。
    (2)基类有同名成员、派生类无,上述方法不可,需通过基类名作用域分辨符实现。

:基类Base1,Base2,都有fun()函数。派生类Derived,没有fun()函数。

方法一:(2)基类名作用域分辨符

Derived d;
d.Base1::fun();
Derived *p=&d;
p->Base2::fun();

方法二:使用using关键字

class Derived:public Base1,public Base2{
public:
    using Base1::fun;
};

上假定基类之间无继承。
若Base1,Base2又有共同基类Base,则Base1,Base2分别继承Base中的fun()函数,Derived中又会同名。
故derived中仍要使用作用域分辨符来唯一标识,并且必须使用直接基类来进行限定。
此种情况派生类成员在内存中同时拥有成员fun()的两份同名副本,有时不需要如此多份,增加了内存开销,故c++提供虚基类解决此种问题。

虚基类

将共同基类设置为虚基类,如此不同路径继承过来的同名数据成员在内存中只有一个副本,同一个函数名也只有一个映射。

class Base0{
public:
    void fun();
};
class Base1:virtual public Base0{};
class Base2:virtual public Base0{};
class Derived:public Base1, public Base2{};
Derived d;
d.fun();

运算符重载

同一个运算符作用于不同类型的数据时导致不同的行为

当运算符重载为类的成员函数时,函数的参数个数比原来的操作数个数要少一个(后置“++”,“--”除外);当重载为非成员函数时,参数个数与原操作数个数相同。原因:重载为类的成员函数时,第一个操作数会被作为函数调用的目的对象;重载为非成员函数时,运算符的所有操作数必须显式通过参数传递。

使用运算符重载实现复数加减法:

#include <iostream>
using namespace std;

class Complex{
public:
    Complex(double r=0.0,double i=0.0):real(r),imag(i){}//构造函数
    Complex operator+ (const Complex &c2) const;
    Complex operator- (const Complex &c1) const;
    void display() const;
private:
    double real;
    double imag;
};

Complex Complex::operator+(const Complex &c2) const{
    return Complex(real+c2.real,imag+c2.imag);
}

Complex Complex::operator-(const Complex &c2) const{
    return Complex(real-c2.real,imag-c2.imag);
}

void Complex::display() const{
    cout<<"("<<real<<","<<imag<<")"<<endl;
}

int main(){
    Complex c1(5,4),c2(2,10),c3;
    cout<<"c1=";c1.display();
    cout<<"c2=";c2.display();
    c3=c1-c2;
    cout<<"c3=c1-c2=";c3.display();
    c3=c1+c2;
    cout<<"c3=c1+c2=";c3.display();
    return 0;
}

运行结果:
图片名称

虚函数

基类类型的指针指向派生类对象时,若基类与派生类中有同名的函数成员,指针首先指向基类的函数成员。
解决方法:虚函数

纯虚函数

基类中可以不给出函数的实现部分

virtual 函数类型 函数名(参数表)=0;
virtual void display() const=0;

抽象类

  • 带有纯虚函数的类
  • 作用:为一个类族建立一个公共的接口,更有效地发挥多态特性。
  • 派生类如果没有给出全部纯虚函数的实现,这时的派生类仍然是一个抽象类。
  • 抽象类不能实例化。不能定义一个抽象类的对象,但可以定义一个抽象类的指针和引用

模板

  • 实现参数化多态性(将程序所处理的对象的类型参数化,使一段程序可以用于处理多种不同类型的对象)

函数模板

  • 对重载的改进
    从函数模板产生的相关函数都是同名的,编译器用重载的方法调用相应的函数。
template<typename T>
T abs(T x){
    return x<0?-x:x;
}
int main(){
    int n=-5;
    double d=-5.5;
    cout<<abs(n)<<endl;
    cout<<abs(d)<<endl;
    return 0;
}

运行结果:
图片名称

类模板

  • 使类中的某些数据成员、某些成员函数的参数、返回值或局部变量能取任意类型。
  • vector就是一个类模板,用vector创建的动态数组都是类模板的对象。
#include <iostream>
#include <cstdlib>
using namespace std;

struct Student{
    int id;
    float gpa;
};

template<class T>//类模板:实现对任意类型数据进行存取
class Store{
private:
    T item;
    bool haveValue;//标记item是否已被存入内容
public:
    Store();
    T &getElem();//提取数据函数
    void putElem(const T &x);//存入数据函数
};

template<class T>//默认构造函数的实现
Store<T>::Store():haveValue(false){}

template<class T>//提取数据函数的实现
T &Store<T>::getElem(){
    if(!haveValue){
        cout<<"No item present!"<<endl;
        exit(1);
    }
    return item;
}

template<class T>
void Store<T>::putElem(const T &x){
    haveValue=true;
    item=x;
}

int main(){
    Store<int> s1,s2;
    s1.putElem(3);
    s2.putElem(-7);
    cout<<s1.getElem()<<" "<<s2.getElem()<<endl;
    Student g={1000,23};
    Store<Student> s3;
    s3.putElem(g);
    cout<<"The student id is"<<s3.getElem().id<<endl;
    Store<double> d;
    cout<<d.getElem()<<endl;
    return 0;
}

运行结果:
图片名称

迭代器

  • 泛化的指针
  • STL算法利用迭代器对存储在容器种的元素序列进行遍历
posted @ 2021-05-15 17:03  菜菜ee  阅读(188)  评论(0)    收藏  举报