C++学习记录

2018-12-30  本文已影响0人  sgy1993

最简单的c++程序

#include <iostream>
int main()
{
    std::cout << "Hello world!" << std::endl;
    return 0;
}

标准输入输出流

可以使用

using namespace std;或者using std::cout;

控制字符,需要包含iomanip

常用的控制字符
setw--默认靠右输出,字符不够,左边补上空格
    cout << setw(4) << 2 << endl;
setw函数演示
setw函数只对靠近自己的字符起作用
    cout << setw(4) << 2 << 3 << endl;
setw函数的作用范围
hex,oct对之前出现的数字不起作用,但是对于之后出现的数字都起作用,也会改变后面的输出
    cout <<12 << hex <<" "<< 16 << " "<< 12 << endl;
    cout << oct << 16 << endl;
hex,oct控制符
setfill的作用,之前setw默认使用空格进行填充,setfill可以改变填充的字符,比如我换成'|',注意这里需要使用单引号
    cout << setfill('|') << setw(10) << 2 << endl;
setfill('|')输出结果

输入相关
cin 可以使用空格,回车,制表符作为 间隔符

string类型

string 可以支持 运算符, >, <, ==, != ,
str.size() 相当于 strlen,也可以使用 str[n]的方式,str.empty();
getline(cin, str)

const char * p_str = str.c_str(); 这个可以获取字符串的地址,但是c++扩充的时候可能会重新释放,分配,所以使用需要注意

Vector类型

定义和初始化Vector类型
Vector有很多操作他的方法
vec.push_back(), vec.size(), vec.pop_back
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;

using std::cout;
using std::endl;
//using std::cin;
int main()
{
    vector<string> v1;
    string str;
    int i = 0;
    while (getline(cin, str)) {
        if (str == "q") {
            break;
        }

        v1.push_back(str);//将这个元素放进vector里面去, pop_back方法是弹出
    }

    cout << v1.size() << endl;
    for (i = 0; i < v1.size(); i++) {
        //str = v1.at(i);取出vector第几个元素出来
        str = v1[i];
        cout << i << ":" << str << ":" <<str.size() << endl;
    }
    return 0;
}
输出结果

引用

int &b = a; //b是a的别名

    cout << "b's address:" << &b << endl;
    cout << "a's address:" << &a << endl;

输出两个的地址,地址是相同的


image.png

引用必须在声明的时候就进行初始化,而且引用一旦与某个变量关联起来,就不会改变。

    int a = 1;
    int c = 20;
    int *pt = &a;
    cout << "pt's address:" << pt << endl;
    int &b = *pt;
    pt = &c;
    cout << "pt's address:" << pt << endl;
    cout << "c's address:" << &c << endl;
    cout << "b's address:" << &b << endl;
    cout << "a's address:" << &a << endl;
//b一开始声明为a的引用,即便pt后来指向了c,b仍然引用的是a
image.png

不同类型的变量不能互相引用,编译器会报错

    int a = 2;
    char &b = a;//invalid initialization of reference of type 'char&' from expression of type 'int'

有一种情况,函数的引用类型和传递过来的不对,会生成临时变量的方式

void func1(const  int &tmp) 

这种形式的好处


image.png
image.png

右值引用


image.png

函数的返回值如果是引用的话,怎么理解

#include <iostream>

using namespace std;
class sgy {
public:
    sgy();
    ~sgy();
private:
    string name;
    int age;
    static int number;
protected:
    int pro_var;
};

sgy::sgy()
{
    this->age = 0;
    this->name = "NULL";
    this->pro_var = 0;
    cout << "sgy()" << endl;
}
sgy::~sgy()
{
     cout << "~sgy()" << endl;
}

int &func2(int &a)
{
    return a;
}
int main()
{
    int a = 2;
    cout << "a's address:" << &a << endl;
    int &b  = func2(a);

    cout << "b's address:" << &b << " b="  << b << endl;

    int c = func2(a);
    cout << "c's address:" << &c << " c="  << c << endl;

    a = 3;

    cout << "a:" << a << "  b:" << b << "   c:" << c << endl;
    return 0;
}

  函数返回的是引用的话,接收的也只能是引用。所以b其实就是a的别名,但是c是独立的变量,
但是c的值是和a的值是一样的,后面即便更改了a的值,b的值会发生变化,但是c的值并不会改变。
image.png

如果上面的例子变成结构体会怎么样呢?

#include <iostream>

using namespace std;
class sgy {
public:
    sgy();
    ~sgy();
private:
    string name;
    int age;
    static int number;
protected:
    int pro_var;
};

sgy::sgy()
{
    this->age = 0;
    this->name = "NULL";
    this->pro_var = 0;
    cout << "sgy()" << endl;
}
sgy::~sgy()
{
     cout << "~sgy()" << endl;
}

struct exam {
    int tmp1;
    int tmp2;
};
exam & func(exam & exam1)
{
    return exam1;
}
int main()
{
    exam ex1;
    ex1.tmp1 = 1;
    ex1.tmp2 = 2;

    exam ex2 = func(ex1);
    cout << "ex2.tmp1:" << ex2.tmp1 << "    ex2.tmp2:" << ex2.tmp2 <<  endl;
    return 0;
}
如果返回的是引用而用结构体直接去接收的话,相当于是把结构体的副本数据接收了过来。看下面的运行结果,类也是一样。
image.png

如果是下面这种情况呢?ex1,ex2的结果是什么

exam &ex2 = func(ex1);//这是正确的使用方法

然后
        exam ex1;
    ex1.tmp1 = 1;
    ex1.tmp2 = 2;
    cout << "ex1's address:" << &ex1 << endl;
    exam &ex2 = func(ex1);
    cout << "ex2.tmp1:" << ex2.tmp1 << "    ex2.tmp2:" << ex2.tmp2 <<  endl;
    cout << "ex2's address:" << &ex2 << endl;
    exam ex3;
    ex3.tmp1 = 3;
    ex3.tmp2 = 4;
    cout << "ex3's address:" << &ex3 << endl;
    ex2 = func(ex3);
    cout << "***************** after func(ex3) ********************" << endl;
    cout << "ex2.tmp1:" << ex2.tmp1 << "    ex2.tmp2:" << ex2.tmp2 <<  endl;
    cout << "ex2's address:" << &ex2 << endl;

image.png

可见引用不会改变,永远指向同一个人,用ex2 去接收一个返回值是引用的这种方式,也是按值传递,即把ex3的数据拷贝一份到ex2里面

函数返回是引用的时候的一些注意事项

image.png
函数的形参是使用const 修饰的情况
void func(const int &a);
这个时候的好处见上面的分析,适用于使用变量的地址,但是又不改变变量的值的情况下。
所以下面的语句会有问题
int &b = a;//const类型的引用不能赋值给常规引用

#const修饰函数返回值的注意事项,const返回值
不能使用常规引用来接收, 但是可以使用同类型的变量来接收,这个时候就是按值进行传递,只能使用const修饰的引用来接收
例如 const int &func(int a);
不能使用 int &a = func(b); 这个会报错。
但是可以使用 int a = func(b); 
int &func(int a)---------这种情况下,返回的引用指向的是一个临时变量
{
    return a;
}

基类引用可以指向派生类对象

这个可以参考一下,讲的挺有用的


image.png
  1. 函数可以有默认的参数
int func(int a=2, int b=3)
注意事项,当有一个变量设置了默认参数,其后的变量都需要有默认参数,否则会报错
int func(int i, int k = 2, int j);

3.函数重载

返回值不同,参数列表相同,不叫函数重载
  1. 函数模板
template <typename T>

T add(T a, T b)
{
    return a + b;
}
函数模板只适用于函数实现相同,形参个数相同,但是函数重载就不限制个数

类和对象

类里面不指定属性的话,就是私有的成员,是不能访问的
class student {
    int i;
    int b;
};
int main()
{
    class student st;
    st.i = 0;//,error: 'int student::i' is private|,会报这个错误
    st.b = 2;
    return 0;
}

类内声明函数,类外定义应该怎么书写;

int class_name::func_name();
int student::get_age();//student 类的get_age函数

每新增加一个类,最好增加一个头文件和源文件的方式

构造函数和析构函数

构造函数没有返回值,函数名称和类名一样

下面是一个简单的构造函数的例子
sgy.h

#ifndef __SGY__H

class sgy {
public:
    sgy();
    void Print_age();
private:
    int age;
};
#endif // __SGY__H

sgy.cpp

#include "sgy.h"
#include <iostream>

using namespace std;
void sgy::Print_age()
{
    cout << age << endl;
}

sgy::sgy()
{
    age = 20;
}

main.cpp

#include <iostream>
#include <iomanip>
#include <vector>
#include "sgy.h"
using namespace std;
int main()
{
    sgy class_sgy;
    class_sgy.Print_age();
    return 0;
}

有参数的构造函数怎么写

    sgy(int i_age);//sgy.h增加这个声明
/*sgy.c中增加这个构造函数的实现*/
sgy::sgy(int i_age)
{
    age = i_age;
}
/*main.cpp里面这样使用*/
    sgy class_sgy(10);
    class_sgy.Print_age();

构造函数声明的时候,参数也是可以使用默认值的

   sgy(int i_age = 20);//sgy.h增加这个声明

析构函数的执行顺序是怎么样的,它不能带任何参数,也没有返回值(包括void类型)

#include <iostream>
#include <iomanip>
#include <vector>
#include "sgy.h"
using namespace std;
sgy g_class_sgy(9);
int main()
{
    sgy class_sgy(10);
    sgy class_sgy1(11);
    sgy class_sgy2(12);
    return 0;
}
/*--------------------------------*/
sgy::~sgy()
{
    cout << "age:" << age << endl;
}

执行析构函数的顺序是,先构造的对象越晚析构

析构函数执行顺序

下面这个例子更清楚一些

/*******************************************************/
#include <iostream>
#include <iomanip>
#include <vector>
#include "sgy.h"
using namespace std;
sgy g_class_sgy(9);
int main()
{
    sgy class_sgy(10);
    sgy class_sgy1(11);
    sgy class_sgy2(12);
    return 0;
}
/*******************************************************/
sgy::sgy(int i_age)
{
    cout << "sgy->i_age:" << i_age << endl;
    age = i_age;
}

sgy::~sgy()
{
    cout << "~sgy->age:" << age << endl;
}

运行结果如下

先构造的函数越晚析构

this指针和复制构造函数,拷贝构造函数

this->类的成员 或者 *(this).类的成员

复制构造函数的执行时机

复制构造函数的执行时机

sgy.h

#ifndef __SGY__H

class sgy {
public:
    sgy();
    sgy(int i_age);
    sgy(sgy &class_sgy);//复制构造函数
    ~sgy();
    void Print_age();
private:
    int age;
};
#endif // __SGY__H

sgy.cpp

#include "sgy.h"
#include <iostream>

using namespace std;
void sgy::Print_age()
{
    cout << age << endl;
}

sgy::sgy()
{
    age = 20;
}

sgy::sgy(int i_age)
{
    cout << "sgy->i_age:" << i_age << endl;
    age = i_age;
}

sgy::~sgy()
{
    cout << "~sgy->age:" << age << endl;
}

sgy::sgy(sgy &class_sgy)
{
    cout << "copy" << endl;
    this->age = class_sgy.age;
}

main.cpp

#include <iostream>
#include <iomanip>
#include <vector>
#include "sgy.h"
using namespace std;

void func(sgy class_sgy)
{
    cout << "func ecexute" << endl;
}
int main()
{
    sgy sgy1(1);

    func(sgy1);
    return 0;
}

运行结果解释,先是执行sgy1的构造,然后执行func函数,执行了类的复制构造函数。

运行结果

以类对象作为函数返回值的情况也会导致复制构造函数被调用

#include <iostream>
#include <iomanip>
#include <vector>
#include "sgy.h"
using namespace std;

sgy class_sgy(10);
void func(sgy class_sgy)
{
    cout << "func ecexute" << endl;
}

sgy func1()
{
   return class_sgy;
}
int main()
{
    sgy sgy1;
    //sgy1 = func1();
    return 0;
}

以类作为返回值的时候,也会调用复制构造函数,或者拷贝构造函数

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;
class sgy {
public:
    sgy();
    sgy(int age, string name);
    sgy(sgy &tmp);
    ~sgy();
    void set_age_name(int age, string name);
    void print_age_name();
    friend sgy operator++(sgy &tmp);
    friend sgy operator++(sgy &tmp, int );

private:
    int age;
    string name;
};
using namespace std;


sgy::sgy()
{
    cout << "default constructor" << endl;
    this->age = 0;
    this->name = "default";
}

sgy::sgy(int age, string name)
{
    cout << "sgy(int age, string name) constructor" << endl;
    this->age = age;
    this->name = name;
}

sgy::sgy(sgy &tmp)
{
    cout << "copy func:" << __func__ << ", line:"<< __LINE__ << endl;
}

sgy::~sgy()
{
    cout << "~sgy:  " << "this->name:" << this->name << endl;
}

void sgy::print_age_name()
{
    cout << "print_info---this->name:" << this->name << "    this->age:" << this->age <<  endl;
}

void sgy::set_age_name(int age, string name)
{
    cout << "func:" << __func__ << ", line:"<< __LINE__ << endl;
    this->age = age;
    this->name = name;
}

sgy operator++(sgy &tmp)
{
    cout << "qqqq,func:" << __func__ << ", line:"<< __LINE__ << endl;
    tmp.age += 1;
    return tmp;
}

sgy operator++(sgy &tmp, int )
{
    cout << "hhhhhh,func:" << __func__ << ", line:"<< __LINE__ << endl;
    tmp.age += 1;
    return tmp;
}

int main()
{
    sgy sgy1(12, "it");
    sgy1++;
    //++sgy1;
    sgy1.print_age_name();
    return 0;
}

执行到后++的重载函数时,返回类,这时调用复制构造函数创建临时变量,然后又析构掉去


image.png

以类的引用作为返回,和以类直接作为返回的区别

/**************
这个不会导致复制构造函数被调用
*/
sgy & sgy_add(sgy &tmp)
{
    return tmp;
}
/*****************************************
而下面这个会调用复制构造函数
*/
sgy sgy_add_exam(sgy &tmp)
{
    return tmp;
}

那么什么时候返回引用,什么时候返回值呢?

m = ++p 可以返回引用,因为返回值和返回引用不影响结果的传递
m = p++;的话不能返回引用,否则m是增加过后的变量
#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;
class sgy {
public:
    sgy();
    sgy(int age, string name);
    ~sgy();
    void set_age_name(int age, string name);
    void print_age_name();
private:
    int age;
    string name;
};
using namespace std;

sgy::sgy()
{
    cout << "default constructor" << endl;
    this->age = 0;
    this->name = "default";
}

sgy::sgy(int age, string name)
{
    cout << "sgy(int age, string name) constructor******>>>>name:" << name  << endl;
    this->age = age;
    this->name = name;
}


sgy::~sgy()
{
    cout << "~sgy:  " << "this->name:" << this->name << endl;
}

void sgy::print_age_name()
{
    cout << "print_info---this->name:" << this->name << "    this->age:" << this->age <<  endl;
}

void sgy::set_age_name(int age, string name)
{
    cout << "func:" << __func__ << ", line:"<< __LINE__ << endl;
    this->age = age;
    this->name = name;
}

int main()
{
    sgy sgy1(12, "it");
    sgy sgy2 = sgy1;
    return 0;
}

上面的代码有什么问题??
sgy1.name 指向的是"it", 而sgy2.name 指向的是同一块内存
运算符 = 号必须作为类内的成员函数来重载
下面的代码会有什么区别??

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;
class sgy {
public:
    sgy();
    sgy(int age, string name);
    sgy(sgy &tmp);
    ~sgy();
    void set_age_name(int age, string name);
    void print_age_name();
    sgy & operator=(sgy &tmp);
private:
    int age;
    string name;
};
using namespace std;

sgy::sgy()
{
    cout << "default constructor" << endl;
    this->age = 0;
    this->name = "default";
}

sgy::sgy(int age, string name)
{
    cout << "sgy(int age, string name) constructor******>>>>name:" << name  << endl;
    this->age = age;
    this->name = name;
}

sgy::sgy(sgy &tmp)
{
    cout << "copy func:" << __func__ << ", line:"<< __LINE__ << endl;
}

sgy::~sgy()
{
    cout << "~sgy:  " << "this->name:" << this->name << endl;
}

void sgy::print_age_name()
{
    cout << "print_info---this->name:" << this->name << "    this->age:" << this->age <<  endl;
}

void sgy::set_age_name(int age, string name)
{
    cout << "func:" << __func__ << ", line:"<< __LINE__ << endl;
    this->age = age;
    this->name = name;
}

sgy & sgy::operator=(sgy &tmp)
{
    cout << "operator=" << endl;
    return tmp;
}
int main()
{
    sgy sgy1(12, "it");

    sgy sgy2 = sgy1;

    sgy sgy3;
    sgy3 = sgy1;
    return 0;
}

    sgy sgy2 = sgy1;----这个不会调用=号的运算符重载函数,而是调用复制构造函数
    sgy sgy3;
    sgy3 = sgy1;------而这个会调用=号的运算符重载函数

image.png

然后析构的顺序是和构造的顺序是相反的。
构造顺序
sgy1---sgy2---sgy3
析构顺序
sgy3---sgy2---sgy1

类的静态成员和静态成员函数

静态成员变量只能在类内声明,类内初始化会报错
private:
    string name;
    int age;
    static int number = 0;
如果类内是这么声明的话,编译器报错
error: ISO C++ forbids in-class initialization of non-const static member 'sgy::number'|

所以需要在sgy.cpp 中进行定义,分配存储空间
int sgy::number = 0;

类的静态成员函数和变量差不多

一般用来访问类的静态成员变量,不能用来访问非静态成员变量和函数
int sgy::getnum()
{
    set_age_name(11, "123");
    return number;
}
会报如下错误
cannot call member function 'int sgy::set_age_name(int, std::string)' without object

const对象和const成员

这两个是等价的
int main()
{
    const sgy sgy1(12, "it");
    sgy sgy2 = sgy1;
    return 0;
}
这样写会报错,为什么呢,sgy1是const对象, 而复制构造函数
sgy::sgy(sgy &tmp)----所以不能把const对象转换为可读可写的引用
const不能调用非const 成员函数和变量

见下面的这个例子

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;
class sgy {
public:
    sgy();
    sgy(int age, string name);
    sgy(const sgy &tmp);
    ~sgy();
    void set_age_name(int age, string name);
    void print_age_name();
    sgy & operator=(sgy &tmp);
private:
    int age;
    string name;
};
using namespace std;

sgy::sgy()
{
    cout << "default constructor" << endl;
    this->age = 0;
    this->name = "default";
}

sgy::sgy(int age, string name)
{
    cout << "sgy(int age, string name) constructor******>>>>name:" << name  << endl;
    this->age = age;
    this->name = name;
}

sgy::sgy(const sgy &tmp)
{
    cout << "copy constructor, func:" << __func__ << ", line:"<< __LINE__ << endl;
}

sgy::~sgy()
{
    cout << "~sgy:  " << "this->name:" << this->name << endl;
}

void sgy::print_age_name()
{
    cout << "print_info---this->name:" << this->name << "    this->age:" << this->age <<  endl;
}

void sgy::set_age_name(int age, string name)
{
    cout << "func:" << __func__ << ", line:"<< __LINE__ << endl;
    this->age = age;
    this->name = name;
}

sgy & sgy::operator=(sgy &tmp)
{
    cout << "operator=" << endl;
    return tmp;
}
int main()
{
    const sgy sgy1(12, "it");
    sgy sgy2 = sgy1;
    sgy1.print_age_name();
    return 0;
}
/*这个例子会报错
要改成这样 void sgy::print_age_name() const--实现的时候
    void print_age_name() const;---声明的时候

*/

友元

    friend void func();
void func()
{
    sgy sgy1(10, "11");
    sgy1.age = 12;
    cout << sgy1.age << endl;
}
可以直接访问类的私有成员, 友元只能授予不能索取,还可以有友元类

运算符重载

运算符重载函数的格式
类的内部作为成员函数实现的声明
    sgy operator+(sgy& sgy_temp0);
两个类相加最终被翻译成现在这个样子
A.operator+(B);
/*****************************   sgy.h    ********************************/
#ifndef __SGY__H
#include <string>
using namespace std;
class sgy {
public:
    sgy();
    sgy(int age, string name);
    ~sgy();
    int set_age_name(int age, string name)
    {
        this->name = name;
        this->age = age;
        return 0;
    }
    void Print_age_name();
    static int getnum();
    friend void func();
    sgy operator+(sgy& sgy_temp0);
private:
    string name;
    int age;
    static int number;
};
#endif // __SGY__H

/*****************************   sgy.cpp    ********************************/
#include "sgy.h"
#include <iostream>

using namespace std;

int sgy::number = 0;
void sgy::Print_age_name()
{
    cout << "age:" << age << ", name:" <<name<< endl;
}

sgy::sgy()
{
    cout << "default constructor" << name;
    age = 0;
    name = "NULL";
    number++;
    cout << "   " << "number:" << number << endl;

}

sgy::sgy(int age, string name)
{
    cout << "sgy(int age, string name):" << name << endl;
    this->age = age;
    this->name = name;
}

sgy::~sgy()
{
    number--;
    cout << "~sgy->name:" << name << "  number:" << number << endl;

}


int sgy::getnum()
{
    //
    return number;
}

sgy sgy::operator+(sgy &sgy_temp0)
{
    string name;
    int age;
    cout << "*******" << sgy_temp0.name  <<"*******"  << this->name << endl;
    age = this->age + sgy_temp0.age;
    name = this->name + sgy_temp0.name;
    sgy sgy1(age,name);
    return sgy1;
}

/*****************************   main.cpp    ********************************/
#include <iostream>
#include <iomanip>
#include <vector>
#include "sgy.h"
using namespace std;

void func()
{
    sgy sgy1(10, "11");
    sgy1.age = 12;
    cout << sgy1.age << endl;
}

int main()
{
    sgy sgy0(1, "sg");
    sgy sgy1(2, "y");
    sgy sgy3(3, "&&");
    sgy sgy2 = sgy0 + sgy1 + sgy3;
    sgy2.Print_age_name();
    return 0;
}

运行结果


运行结果

运算符重载的规则

可以重载的运算符


规则

重载单目运算符

int operator++() ------->这个相当于是++a;
int operator++(int)------>这个相当于是a++;
#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;
class sgy {
public:
    sgy();
    sgy(int age, string name);
    sgy(sgy &tmp);
    ~sgy();
    void set_age_name(int age, string name);
    void print_age_name();
    friend sgy operator++(sgy &tmp);
    friend sgy operator++(sgy &tmp, int );
    friend ostream & operator<<(ostream &output, sgy &tmp);
private:
    int age;
    string name;
};
using namespace std;


sgy::sgy()
{
    cout << "default constructor" << endl;
    this->age = 0;
    this->name = "default";
}

sgy::sgy(int age, string name)
{
    cout << "sgy(int age, string name) constructor" << endl;
    this->age = age;
    this->name = name;
}

sgy::sgy(sgy &tmp)
{
    cout << "copy func:" << __func__ << ", line:"<< __LINE__ << endl;
}

sgy::~sgy()
{
    cout << "~sgy:  " << "this->name:" << this->name << endl;
}

void sgy::print_age_name()
{
    cout << "print_info---this->name:" << this->name << "    this->age:" << this->age <<  endl;
}

void sgy::set_age_name(int age, string name)
{
    cout << "func:" << __func__ << ", line:"<< __LINE__ << endl;
    this->age = age;
    this->name = name;
}

sgy operator++(sgy &tmp)
{
    cout << "qqqq,func:" << __func__ << ", line:"<< __LINE__ << endl;
    tmp.age += 1;
    return tmp;
}

sgy operator++(sgy &tmp, int )
{
    cout << "hhhhhh,func:" << __func__ << ", line:"<< __LINE__ << endl;
    tmp.age += 1;
    return tmp;
}
ostream & operator<<(ostream &output, sgy &tmp)
{
    cout << "********   " << "age:" << tmp.age << ",name:" << tmp.name <<  "  *************";
    return output;
}
int main()
{
    sgy sgy1(12, "it");
    sgy1++;
    //++sgy1;
    sgy1.print_age_name();
    return 0;
}

上面的代码可以直接运行

重载流插入,流提取运算符

这两个运算符只能作为普通函数,不能作为类的成员函数实现
image.png

下面写几个关于流运算符重载的例子,流运算符只能用作普通函数

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;
class sgy {
public:
    sgy();
    sgy(int age, string name);
    sgy(sgy &tmp);
    ~sgy();
    void set_age_name(int age, string name);
    void print_age_name();
    friend ostream & operator<<(ostream &output, sgy &tmp);
    friend istream & operator>>(istream &input, sgy &tmp);
private:
    int age;
    string name;
};
using namespace std;

sgy::sgy()
{
    cout << "default constructor" << endl;
    this->age = 0;
    this->name = "default";
}

sgy::sgy(int age, string name)
{
    cout << "sgy(int age, string name) constructor******>>>>name:" << name  << endl;
    this->age = age;
    this->name = name;
}

sgy::sgy(sgy &tmp)
{
    cout << "copy func:" << __func__ << ", line:"<< __LINE__ << endl;
}

sgy::~sgy()
{
    cout << "~sgy:  " << "this->name:" << this->name << endl;
}

void sgy::print_age_name()
{
    cout << "print_info---this->name:" << this->name << "    this->age:" << this->age <<  endl;
}

void sgy::set_age_name(int age, string name)
{
    cout << "func:" << __func__ << ", line:"<< __LINE__ << endl;
    this->age = age;
    this->name = name;
}

ostream & operator<<(ostream &output, sgy &tmp)
{
    cout << "operator<< overload  " << "age:" << tmp.age << ",name:" << tmp.name <<  "  *************" << endl;
    return output;
}

istream & operator>>(istream &input, sgy &tmp)
{
    cin >> tmp.age >> tmp.name;
    return input;
}
int main()
{
    sgy sgy1(12, "it");
    cin >> sgy1;
    cout << sgy1;
    return 0;
}

运行结果


image.png image.png

运算符重载本质上也是一个函数,也可以直接调用

image.png

类的内部也可以定义重载函数,不过格式就不一样了

类的内部的函数,一般都是p.operator+(),所以就不需要传递两个参数了

类型转换

image.png image.png

继承与派生

继承和派生的格式

image.png

接下来是一个实际的例子

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;
class sgy {
public:
    sgy();
    sgy(int age, string name);
    //sgy(sgy &tmp);
    ~sgy();
    void set_age_name(int age, string name);
    void print_age_name();

    const sgy & sgy_add(sgy &tmp);
private:
    int age;
    string name;
};
using namespace std;

sgy::sgy()
{
    cout << "default constructor" << endl;
    this->age = 0;
    this->name = "default";
}

sgy::sgy(int age, string name)
{
    cout << "sgy(int age, string name) constructor******>>>>name:" << name  << endl;
    this->age = age;
    this->name = name;
}

#if 0
sgy::sgy(sgy &tmp)
{
    cout << "copy constructor, func:" << __func__ << ", line:"<< __LINE__ << ", name:" << tmp.name << endl;
}
#endif

sgy::~sgy()
{
    cout << "~sgy:  " << "this->name:" << this->name << endl;
}

void sgy::print_age_name()
{
    cout << "print_info---this->name:" << this->name << "    this->age:" << this->age <<  endl;
}

void sgy::set_age_name(int age, string name)
{
    cout << "func:" << __func__ << ", line:"<< __LINE__ << endl;
    this->age = age;
    this->name = name;
}

class sgy_inherit : public sgy {

};

int main()
{
    sgy_inherit sgy1;
    sgy1.set_age_name(12, "it");
    sgy1.print_age_name();
    return 0;
}

class sgy_inherit : public sgy {
};//表示sgy_inherit 从 sgy继承而来

1. 派生类不能够访问基类的私有成员

下面这样的写法是会报错的,因为sgy_inherit 的类内成员函数访问不了基类的私有成员。

class sgy_inherit : public sgy {
    int get_age();
};

int sgy_inherit::get_age()
{
    return this->age;
}

派生类的类内成员函数可以访问基类的protected成员,不能直接在类外进行访问,类似于 class_xxx.var 的形式

派生类可以调整由基类继承过来的变量的权限,派生类可见的变量和函数的权限

使用下面的方式即可,对private不可以这么做

class sgy_inherit : public sgy {
private:
public:
    using sgy::protect_var;
};

也可以将函数的权限进行调整

class sgy_inherit : public sgy {
private:
    using sgy::print_age_name;
public:
    using sgy::protect_var;
};

访问权限的总结

image.png

看下面的实际例子

class sgy_inherit_public : public sgy {
};

class sgy_inherit_protected : protected sgy {
};

class sgy_inherit_private : private sgy {
};

int main()
{
    sgy_inherit_public sgy_public;
    sgy_inherit_protected sgy_protected;
    sgy_inherit_private sgy_private;

    sgy_public.print_age_name();
    //sgy_protected.print_age_name();//protected不能在类的外部直接使用
    //sgy_private.print_age_name();//private继承下来还是private的,所以也不能直接访问

    return 0;
}

派生类可以重新实现基类的函数

class CCurrentTime : public CTime 派生类的声明

派生类的方法和基类的方法同名的时候会优先调用派生类的方法

class sgy_inherit_public : public sgy {
 public:
    void print_age_name();
};
/*这里把基类的这个函数重写了,不会调用基类的函数,而是调用派生类的这个函数*/
void sgy_inherit_public::print_age_name()
{
    cout << "inherit func overrite" << endl;
}
int main()
{
    sgy_inherit_public sgy_public;
    sgy_public.print_age_name();
    return 0;
}

派生类是一个基类对象,可以将派生类直接赋值给基类

多重继承

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;


class CSofa {
public:
    void WatchTv() {
        cout << "func:" << __func__ << endl;
    }
};

class CBed {
public:
    void Sleep() {
        cout << "func:" << __func__ << endl;
    }
};

class CSofaBed: public CSofa, public CBed {

};
int main()
{
    CSofaBed CSofaBed1;
    CSofaBed1.WatchTv();
    CSofaBed1.Sleep();
    return 0;
}

输出结果


image.png

虚拟基类继承

虚拟基类的构造函数只会执行一次

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;


class CFurniture {
private:
    int m_iWeight;
public:
    void m_SetWeight(int iWeight) { this->m_iWeight = iWeight; }
    int m_GetWeight(void) const { return this->m_iWeight; }
};

class CSofa : virtual public CFurniture{
public:
    void WatchTv() {
        cout << "func:" << __func__ << endl;
    }
};

class CBed : virtual public CFurniture {
public:
    void Sleep() {
        cout << "func:" << __func__ << endl;
    }
};

class CSofaBed: public CSofa, public CBed {

};
int main()
{
    CSofaBed CSofaBed1;
    CSofaBed1.WatchTv();
    CSofaBed1.Sleep();

    CSofaBed1.m_SetWeight(100);
    cout << CSofaBed1.m_GetWeight() << endl;
    return 0;
}

构造函数的执行顺序,构造函数顺序

image.png

实例展示

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;


class CFurniture {
private:
    int m_iWeight;
public:
    void m_SetWeight(int iWeight) { this->m_iWeight = iWeight; }
    int m_GetWeight(void) const { return this->m_iWeight; }
    CFurniture() {
        cout << "func:" << __func__ << " constructor" << endl;
    }
};

class CVertification3C {
public:
    CVertification3C() {
        cout << "func:" << __func__ << " constructor" << endl;
    }
};

class CSofa : virtual public CFurniture, virtual public CVertification3C{
public:
    void WatchTv() {
        cout << "func:" << __func__ << endl;
    }
    CSofa() {
        cout << "func:" << __func__ << " constructor" << endl;
    }

};

class CBed : virtual public CFurniture, virtual public CVertification3C {
public:
    void Sleep() {
        cout << "func:" << __func__ << endl;
    }
    CBed() {
        cout << "func:" << __func__ << " constructor" << endl;
    }
};

class CSofaBed: public CSofa, public CBed {
public:
    CSofaBed() {
        cout << "func:" << __func__ << " constructor" << endl;
    }
};

class CLeftRightCom {
public:
    CLeftRightCom() {
        cout << "func:" << __func__ << " constructor" << endl;
    }
};

class Date {
public:
    Date() {
        cout << "func:" << __func__ << " constructor" << endl;
    }
};

class Type {
public:
    Type() {
        cout << "func:" << __func__ << " constructor" << endl;
    }
};


class CLeftRightSofabed : public CSofaBed,  virtual public CLeftRightCom {
private:
    Date date;
    Type type;

public:
    CLeftRightSofabed() {
        cout << "func:" << __func__ << " constructor" << endl;
    }

};
int main()
{
    CLeftRightSofabed s;
    return 0;
}

执行结果

func:CFurniture constructor
func:CVertification3C constructor
func:CLeftRightCom constructor
func:CSofa constructor
func:CBed constructor
func:CSofaBed constructor
func:Date constructor
func:Type constructor
func:CLeftRightSofabed constructor

多重继承怎么给构造函数传递参数

如果是父类就写类名,如果是子类就写变量的名字
    LeftRightSofabed(char *str1, char *str2, char *str3) : Sofabed(str1), LeftRightCom(str2), date(str3) { cout <<"LeftRightSofabed()"<<endl; }

三种属性的比较

第一: private,public,protected的访问范围:

private: 只能由该类中的函数、其友元函数访问,不能被任何其他访问,该类的对象也不能访问.
protected: 可以被该类中的函数、子类的函数、以及其友元函数访问,但不能被该类的对象访问
public: 可以被该类中的函数、子类的函数、其友元函数访问,也可以由该类的对象访问
注:友元函数包括两种:设为友元的全局函数,设为友元类中的成员函数

第二:类的继承后方法属性变化:

使用private继承,父类的所有方法在子类中变为private;
使用protected继承,父类的protected和public方法在子类中变为protected,private方法不变;
使用public继承,父类中的方法属性不发生改变;

对于同一类
protected成员不允许类对象直接访问,和private一样。

#include <iostream>
using namespace std;
class sgy {
public:
    sgy();
    ~sgy();
private:
    string name;
    int age;
    static int number;
protected:
    int pro_var;
};

sgy::sgy()
{
    this->age = 0;
    this->name = "NULL";
    this->pro_var = 0;
    cout << "sgy()" << endl;
}

int main()
{
    sgy sgy1;
    sgy1.pro_var = 0;//这样写会报错,sgy::pro_var' is protected
    return 0;
}

多态

多态为什么会出现

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;

class CHuman {
public:
    void m_Eating() {
        cout << "func:"  << __func__  << ", CHuman" << endl;
    }
};

class CEnglishMan : public CHuman {
public:
    void m_Eating() {
        cout << "func:"  << __func__  << ", CEnglishMan" << endl;
    }
};

class CChineseMan : public CHuman {
public:
    void m_Eating() {
        cout << "func:"  << __func__ << ", CChineseMan" << endl;
    }
};

void TestEating(CHuman &h)
{
    h.m_Eating();
}

int main()
{
    CHuman h;
    CEnglishMan e;
    CChineseMan c;

    TestEating(h);
    TestEating(e);
    TestEating(c);
    return 0;
}

执行结果

func:m_Eating, CHuman
func:m_Eating, CHuman
func:m_Eating, CHuman

改成这样声明之后,

class CHuman {
public:
    virtual void m_Eating() {
        cout << "func:"  << __func__  << ", CHuman" << endl;
    }
};

执行结果

func:m_Eating, CHuman
func:m_Eating, CEnglishMan
func:m_Eating, CChineseMan

使用func(a++);传递的时候,传过来的值是多少
a = 2, func接收到的值也是2

内联函数与宏的区别
内联函数还是按照函数的按值传递,宏是直接按文本进行替换

#define square(x) x*x
inline dobule square(dobule x);

同样是square(4.5+7.5),inline 计算的是12的平方,而宏则是 4.5+7.5 * 4.5+7.5

new 运算符

int *ptr = new int [10];
delete [] ptr

    int *p_i = new int (6);//将其初始化为6
image.png

使用new和delete的注意事项


image.png

第9章 内存模型和名称空间

声明区域和潜在作用域


image.png image.png image.png

using声明和using编译指令
using声明将特定的名称添加到它所属的声明区域中。

#include <stdio.h>
namespace sgy {
    int sgy11;    
};

using sgy::sgy11;
int sgy11;
int main()
{
    
    return 0;
}

但是像上面那样定义是有问题的,不能都放在全局的命名空间中
可以向下面这样使用。

#include <stdio.h>

namespace sgy {
    int sgy11;    
};


int sgy11 = 3;
int main()
{
    using sgy::sgy11;
    sgy11 = 2;
    printf("sgy11:%d, 全局sgy11:%d\n", sgy11, ::sgy11);
    
    return 0;
}

输出结果如下,引用全局变量可以使用::var的方法

sgy@ubuntu:~/sgy/user_program/c++$ ./test
sgy11:2, 全局sgy11:3
sgy@ubuntu:~/sgy/user_program/c++$

using namespace sgy----using编译指令会使名称空间中所有的名称可用。但是不会引起报错,如果名称空间中有同名的变量。

#include <stdio.h>

namespace sgy {
    int sgy11 = 100;    
};


//int sgy11 = 3;
int main()
{
    using namespace sgy;
    int sgy11 = 3;    
    //sgy11 = 2;
    printf("sgy11:%d\n", sgy11);
    printf("namespace sgy::sgy11:%d\n", sgy::sgy11);
    return 0;
}

上面使用using namespace sgy; 虽然名称空间中sgy也有一个变量,但是这样不会引起名称冲突,但是如果使用的是 using sgy::sgy11; 这样的方式将会报错

注意:


image.png
#include <stdio.h>

namespace sgy {
    int sgy11 = 100;    
};

int sgy11 = 40;
using namespace sgy;
int main()
{
    int sgy11 = 3;    
    //sgy11 = 2;
    printf("sgy11:%d\n", sgy11);
    printf("sgy11:%d\n", ::sgy11);

    printf("namespace sgy::sgy11:%d\n", sgy::sgy11);
    return 0;
}

上面的这个例子足以说明效果,输出结果见下方

sgy@ubuntu:~/sgy/user_program/c++$ ./test
sgy11:3
sgy11:40
namespace sgy::sgy11:100

名称空间的嵌套和名称空间的别名


image.png

未命名的名称空间


C++类构造函数初始化列表

问题和注意事项

1. sgy sgy2(); 这是一个函数声明,不是一个类的实例化,

例如下面的程序输出结果

#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;
class sgy {
public:
    sgy();
    sgy(int age, string name);
    ~sgy();
    void set_age_name(int age, string name);
    void print_age_name(int age, string name);

private:
    int age;
    string name;
};
using namespace std;


sgy::sgy()
{
    cout << "default constructor" << endl;
    this->age = 0;
    this->name = "default";
}

sgy::sgy(int age, string name)
{
    cout << "sgy(int age, string name) constructor" << endl;
    this->age = age;
    this->name = name;
}
sgy::~sgy()
{
    cout << "~sgy:  " << "this->name:" << this->name << endl;
}

void sgy::print_age_name(int age, string name)
{
    cout << "this->name:" << this->name << "this->age:" << this->age <<  endl;
}

void sgy::set_age_name(int age, string name)
{
    this->age = age;
    this->name = name;
}


int main()
{
    sgy sgy1(12, "it");
    sgy *ptr = &sgy1;
    sgy *ptr1 = &sgy1;
    sgy sgy2();
    return 0;
}

image.png

可见 sgy sgy2(); 并没有调用构造函数

//备份一部分代码
#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;
class sgy {
public:
    sgy();
    sgy(int age, string name);
    ~sgy();
    void set_age_name(int age, string name);
    void print_age_name();
    friend void operator++(sgy &tmp);
    friend void operator++(sgy &tmp, int );

private:
    int age;
    string name;
};
using namespace std;


sgy::sgy()
{
    cout << "default constructor" << endl;
    this->age = 0;
    this->name = "default";
}

sgy::sgy(int age, string name)
{
    cout << "sgy(int age, string name) constructor" << endl;
    this->age = age;
    this->name = name;
}
sgy::~sgy()
{
    cout << "~sgy:  " << "this->name:" << this->name << endl;
}

void sgy::print_age_name()
{
    cout << "this->name:" << this->name << "    this->age:" << this->age <<  endl;
}

void sgy::set_age_name(int age, string name)
{
    this->age = age;
    this->name = name;
}

void operator++(sgy &tmp)
{
    cout << "func:" << __func__ << ", line:"<< __LINE__ << endl;
    tmp.age += 1;
}

void operator++(sgy &tmp, int )
{
    cout << "func:" << __func__ << ", line:"<< __LINE__ << endl;
    tmp.age += 1;
}

int main()
{
    sgy sgy1(12, "it");
    sgy1++;
    //++sgy1;
    sgy1.print_age_name();
    return 0;
}

delete 与 delete[] 区别:

1、针对简单类型 使用 new 分配后的不管是数组还是非数组形式内存空间用两种方式均可 如:

int *a = new int[10];   
delete a;   
delete [] a; 

此种情况中的释放效果相同,原因在于:分配简单类型内存时,内存大小已经确定,系统可以记忆并且进行管理,在析构时,系统并不会调用析构函数, 它直接通过指针可以获取实际分配的内存空间,哪怕是一个数组内存空间(在分配过程中 系统会记录分配内存的大小等信息,此信息保存在结构体_CrtMemBlockHeader中, 具体情况可参看VC安装目录下CRT\SRC\DBGDEL.cpp)

2、针对类Class,两种方式体现出具体差异

当你通过下列方式分配一个类对象数组:

class A
{
    private:
        char *m_cBuffer;
        int m_nLen;
    public:
        A(){ m_cBuffer = new char[m_nLen]; }
        ~A() { delete [] m_cBuffer; }
};
A *a = new A[10];

// 仅释放了a指针指向的全部内存空间 但是只调用了a[0]对象的析构函数 剩下的从a[1]到a[9]这9个用户自行分配的m_cBuffer对应内存空间将不能释放 从而造成内存泄漏
delete a;

// 调用使用类对象的析构函数释放用户自己分配内存空间并且 释放了a指针指向的全部内存空间
delete [] a;
所以总结下就是,如果ptr代表一个用new申请的内存返回的内存空间地址,即所谓的指针,那么:

delete ptr -- 代表用来释放内存,且只用来释放ptr指向的内存。
delete[] rg -- 用来释放rg指向的内存,!!还逐一调用数组中每个对象的 destructor!!
对于像 int/char/long/int*/struct 等等简单数据类型,由于对象没有 destructor,所以用 delete 和 delete [] 是一样的!但是如果是C++ 对象数组就不同了!

问题:

有 const 修饰的成员函数(指 const 放在函数参数表的后面,而不是在函数前面或者参数表内),只能读取数据成员,不能改变数据成员;没有 const 修饰的成员函数,对数据成员则是可读可写的。

成员初始化列表

sgy::sgy(int age, int index) : age(age), index(index)

隐式转换发生的时机


image.png

const 指针和const 修饰的变量


image.png

双冒号(::)用法

  1. 作用域限定符,当在类体中直接定义函数时,不需要在函数名字的前面加上类名,但是在类体外实现函数定义的时候,必须加上类名并且加上作用域限定符。Student::Display();

  2. 静态数据成员既可以通过对象名引用,也可以通过类名加::来引用

  3. 静态成员函数,也是既可以通过对象名引用,也可以通过类名+::引用。

感觉这篇文章写得挺好的
https://blog.csdn.net/lixungogogo/article/details/51118524

C++ 子类对象当父类对象使用, 给下面的print函数加上virtual,还只能加在父类里面才管用

#include <iostream>


using namespace std;


class Base
{
public:
int a;
Base()
{
a = 0;
cout << "I`m base Begin" << endl;
}
void Print()
{
cout << "father: a=" <<a << endl;
}
~Base()
{
cout << "I`m base End" << endl;
}
};


class Simple : public Base
{
public:
int a;
Simple()
{
a = 1;
cout << "I`m Simple Begin" << endl;
}
virtual ~Simple()
{
cout << "I`m Simple End" << endl;
}
void Print()
{
cout<< "child: a=" <<a<<endl;
}
};


int main()
{
Simple b;


Base *pBase = &b;//多态看的是指针所指向的类型来调用


b.Print();//这个地方是simple 也就是child 1
cout << b.a << endl;
cout << pBase->a << endl;
pBase->Print();

return 0;
}

Base *pBase = &b;//多态看的是指针所指向的类型来调用
如果不是虚函数的话,调用的是base->print, 如果是多态的话,调用的是指向的类型的print函数

1 前言  
  记得当初阿里面试的时候被问道这个问题,平时自己面对这个方法都习以为常的使用,C++多态和动态绑定不就是这么实现的嘛,但是还真没有刻意去关注其中的原理。今天特意看了相关资料,现在分享给大家。
  其实这块我们需要分为两种情况来考虑,第一种是类继承(静态绑定),第二种是父类中包含虚函数(动态绑定)。
2 具体实现  
 2.1 没有虚函数的继承
  如果以一个基础类指针指向一个派生类对象,那么经由该指针只能访问基础类定义的函数(静态绑定)。
  如果以一个派生类类指针指向一个基础类对象,必须先做强制转型动作(explicit cast),这种做法很危险,也不符合生活习惯,在程序设计上也会给程序员带来困扰。(一般不会这么去使用)
  如果基础类和派生类类定义了相同名称的成员函数,那么通过对象指针调用成员函数时,到底调用那个函数要根据指针的原型来确定,而不是根据指针实际指向的对象类型确定。(指针类型是谁就调用谁)
  这块我需要说明一下为何基础类可以指向派生类对象,而派生类不去指向父类对象。
  通常来说,子类总是含有一些父类没有的成员变量,或者方法函数。而子类肯定含有父类所有的成员变量和方法函数。所以用父类指针指向子类时,没有问题,因为父类有的,子类都有,不会出现非法访问问题。
  但是如果用子类指针指向父类的话,一旦访问子类特有的方法函数或者成员变量,就会出现非法,因为被子类指针指向的由父类创建的对象,根本没有要访问的那些内容,那些是子类特有的,只有用子类初始化对象时才会有。
 2.2 包含虚函数的继承
  有虚函数的继承,那么父类指针指向子类对象就是我们常见的多态实现,也就是动态绑定。
  虚拟函数就是为了对“如果你以一个基础类指针指向一个衍生类对象,那么通过该指针,你只能访问基础类定义的成员函数”这条规则反其道而行之的设计。
  当然这里还包括纯虚拟函数,只要是拥有纯虚拟函数的类,就是抽象类,它们是不能够被实例化的(只能被继承)。如果一个继承类没有改写父类中的纯虚函数,那么他也是抽象类,也不能被实例化。抽象类不能被实例化,不过我们可以拥有指向抽象类的指针,以便于操纵各个衍生类。
2 总结 
  当定义一个指向子类实例的父类指针的时候,内存中实例化了子类,由于子类继承了父类,因此内存中的子类里包含父类的所有成员。但由于生命的时父类指针,因此该指针不能够访问子类的成员,而只能访问父类的成员。然而在父类里可以声明纯虚函数和定义虚函数,使用父类指针访问虚函数或纯虚函数的时候,访问到的是子类里重写的函数。当然,对于虚函数,如果子类里没有对其重写的话,仍然访问到父类里定义的虚函数。可见虚函数和纯虚函数的却别仅仅在于:纯虚函数没有定义,只有声明。

C++模板

C++ 模板详解(一)

注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。

类模板演示的实际例子

template<class T> class A{//类模板的声明写什么样子
    public:
        T g(T a,T b);
        A();
};

template<class T> A<T>::A(){}
template<class T> T A<T>::g(T a,T b){
    return a+b;
}

int main(){
    A<int> a;//类模板的实例化,所有用到T的地方全部都用int代替
    cout<<a.g(2,3.2)<<endl;
}

类模板定义好之后,怎么定义类外的成员函数

4、在类模板外部定义成员函数的方法为:
    template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},

比如有两个模板形参T1,T2的类A中含有一个void h()函数,则定义该函数的语法为:
    template<class T1,class T2> void A<T1,T2>::h(){}。

强制类型转换
C++四种类型转换运算符:static_cast、dynamic_cast、const_cast和reinterpret_cast

C++ Template 基础篇(一):函数模板

虚拟继承为什么要出现

#include <iostream>

using namespace std;
class A {
public:
    int m_a;
};

//直接基类B
class B: public A{
public:
    int m_b;
};


//直接基类C
class C: public A{
public:
    int m_c;
};

//派生类D
class D: public B, public C{
public:
    void seta(int a){ m_a = a; }  //命名冲突,这个地方可能从B继承来的m_a, 也有可能是从C继承来的m_a
};

int main()
{
    D d;
    return 0;
}

子类继承父类之后,如果有同名的函数或者变量,首先访问的是子类的同名成员函数或者变量

#include <iostream>
#include <stdio.h>
using namespace std;
class A {
public:
    int m_a;
};

//直接基类B
class B: public A{
public:
    int m_b;
    B() {
        m_a = 2;
        printf("B的构造函数\n");
    }
    void print() {
        m_a = 3;
        printf("现在调用的是B里面的print函数, m_a = %d\n", m_a);
    }
};


//直接基类C
class C: public A{
public:
    int m_c;
    C() {
        m_a = 4;
        printf("c的构造函数\n");
    }
};

//派生类D
class D: public B, public C{
public:
    //void seta(int a){ m_a = a; }  //命名冲突,这个地方可能从B继承来的m_a, 也有可能是从C继承来的m_a
    void print();
};


void D::print() {
    B::print();
    printf("B::m_a:%d, C::m_a:%d\n", B::m_a, C::m_a);
}

int main()
{
    D d;
    d.print();
    d.B::print();//显示的调用B里面的print函数
    return 0;
}

比如上面 D继承于B, B和D里面都有print函数,那么D怎么能够使用到B里面的成员函数呢?

  1. B::print----->这个是在类的内部使用的,
  2. d.B::print---->这个是在类的外部使用的方式

下面这个函数访问的是子类的同名函数而不会访问父类里面的

#include <iostream>
#include <stdio.h>
using namespace std;
class A {
public:
    int m_a;
};

//直接基类B
class B: public A{
public:
    int m_b;
    B() {
        m_a = 2;
        printf("B的构造函数\n");
    }
    void print() {
        m_a = 3;
        printf("现在调用的是B里面的print函数, m_a = %d\n", m_a);
    }
};


//直接基类C
class C: public A{
public:
    int m_c;
    C() {
        m_a = 4;
        printf("c的构造函数\n");
    }
};

//派生类D
class D: public B, public C{
public:
    //void seta(int a){ m_a = a; }  //命名冲突,这个地方可能从B继承来的m_a, 也有可能是从C继承来的m_a
    void print();
    void print1() {
        print();
    }
};


void D::print() {
    //B::print();
    printf("D类, B::m_a:%d, C::m_a:%d\n", B::m_a, C::m_a);
}

int main()
{
    D d;
    d.print1();
    //d.B::print();//显示的调用B里面的print函数
    return 0;
}

使用函数默认参数有哪些需要注意的事项

#include <stdio.h>
class sgy {
public:
    int age;
    sgy();
    sgy (int age = 12);
};

sgy::sgy()
{
    printf("默认的构造函数\n");
}

sgy::sgy(int age)
{
    printf("sgy(int age)构造函数\n");
    
}

int main()
{
    sgy sgy1; 
    return 0;
}

上面的代码会报错,报错的原因是因为不知道使用哪一个构造函数, 因为默认参数指定的情况下,两个函数都满足情况,所以不知道调用哪一个,报错。

root@iZ2ze9yqb3xdqngyx445idZ:~/sgy/test# g++ -o main main.cpp
main.cpp: In function ‘int main()’:
main.cpp:110:9: error: call of overloaded ‘sgy()’ is ambiguous
     sgy sgy1;
         ^
main.cpp:102:1: note: candidate: sgy::sgy(int)
 sgy::sgy(int age)
 ^
main.cpp:97:1: note: candidate: sgy::sgy()
 sgy::sgy()
 ^
root@iZ2ze9yqb3xdqngyx445idZ:~/sgy/test#
上一篇 下一篇

猜你喜欢

热点阅读