C++基础

来源:互联网 发布:网络直播怎么兴起的 编辑:程序博客网 时间:2024/06/16 02:03

一,C++对C一些扩展的学习

1,namespace使用和注意点

namespace的定义的

1,namepspace命名空间的里面变量的作用域声明必须是全局变量

namespace LOL{    const int a = 90;  //声明成全局变量    void test();}

2, 命名空间存在的意义是避免二义性

解释:就是变量的在不同的命名空间就前面加上命名空间, 在C语言中这样的定义使用会重名

3,命名空间可以有变量,函数,结构体,类

4,命名空间可以圈套命名空间

namespace LOL1{    int a = 90;    namespace chen    {        int b = 80;    }}//命名空间取别名namespace che = LOL1;

5,命名空间可以后期扩展, 同名的不会覆盖 而是合并

6,命名空间可以匿名

7,命名空间可以起别名

2,using声明以及using编译指令

using 声明碰到函数重载

namespace A{void func(){}void func(int x){}int  func(int x,int y){}}void test(){    using A::func;    func();    func(10);    func(10, 20);}

3,C++ 对C的增强

1,全局变量检测的增强

下面代码在C中可以C++不可以

int a;int a = 80; 
2.函数检测
1.参数类型检测
//函数在C语言中不用写明函数参数的类型而在C++中必须写类型int myswap(a, b);  
2.返回值的检测

在C语言中可以不用写函数的返回值编译器会waring ,C++必须要有返回值

int myswap(a, b){};
3,函数调用 传参个数

在C语言中可以传入多个参数,在C++中可以传多个参数
int myswap(int a, int b);

int main(void){    myswap(89, 90, 89, 89); //在C语言中可以传入多个参数return 0;}
3,类型转换增强

C++中malloc后必须转换为 需要的类型

4,struct增强
1,C++中可以放函数
2,C++中使用结构体, 可以省略关键字
3,bool类型
sizeof bool = 1
4,三目运算符增强
C++中返回 变量 可以继续作为左值运算
int a = 10;int b = 20;printf("ret:%d\n", a > b ? a : b);//思考一个问题,(a > b ? a : b) 三目运算表达式返回的是什么?cout << "b:" << b << endl;//返回的是左值,变量的引用(a > b ? a : b) = 100;//返回的是左值,变量的引用cout << "b:" << b << endl;

三目运算的本质是:

*(a > b ? &a : &b ) = 100;
5,const增强
1,C和C++对const处理的方式

C语言中 局部的const变量 会分配内存, 可以通过指针间接修改,为常量,不许初始化数组

C++中局部的const 会放到符合表中,不可以通过指针修改到本体,可以作为为常量 初始化数组

const在C语言中默认是外部链接,可以在其他文件中进行访问

const在C++中 默认是内部链接,需要利用extern提供作用域,改成外部链接

4,引用的基本语法

引用实际是变量的别名吧了

int u = 90;int const *p = u;
1,语法

语法:类型 &别名 = 原名

2,引用必须要初始化 一旦初始化后就不可以修改指向
int a1 = 90;int &b1 = a1;int &b1 = a; //err
3,对数组建立引用的操作
int arr[] = { 4, 45, 454, 34, 9 };//方法一:int(&aprr)[5] = arr;int i;for (i = 0; i < 5; i++)    cout << aprr[i] << endl;//方法二typedeftypedef int parr[5];parr& p = arr;for (i = 0; i < 5; i++)    cout << p[i] << endl;
4,函数参数的是引用
//引用的使用void set_name(char* &name)  //实际还是地址引用{    n_name = name;}

二,函数重载和类的封装

1,C++函数的默认参数

1,语法:

语法: 类型 变量名称 = 默认值

void load(int a = 90000, int b = 100) ///默认值{    cout << "a = " << a << "b = " << b << endl;}int main(void){    load(3, 9);   //    system("pause");    return 0;}

默认参数会被转过去的值输替代

运行效果图

2,参数中有一个参数有了默认值, 那该位置开始从左到右都必须有默认值

例子:

void load(int a, int b = 90, int c = 1000, int d = 440){    cout << "a = " << a << "b = " << b << "c = " << c         << "d = " << d << endl;}int main(void){    load(3, 4, 5, 6);  //参数    system("pause");    return 0;}
3,当函数的声明和实现中, 只能有一个出现默认参数
void load(int a, int b);void load(int a, int b, int c, int d);

2,占位符参数

占位符不能使用在头文件中, 占位符是默认值相当于没有

例子:

//占位符void placeholder2(int a, int = 90)  //占位符 int = 90{    cout << "a = " << a << endl;}int main(void){    //占位符    placeholder2(9000);    system("pause");    return 0;}

3,函数重载

  1. 在同一作用域下
  2. 函数的参数不同, 或者类型不同, 或者顺序不同
  3. 函数的返回值不能作为重载的条件
1,重载
//函数的重载方法名相同参数不同void overload(){    cout << "overload()" << endl;}void overload(int a){    cout << "overload(int a)" << endl;}void overload(int a, int b){    cout << "overload(int a, int b)" << endl;}
2,引用重载

例子1.

void referen(int& a)  //int const * a //引用是一块内存的空间  //没有内存空间是不可以的{    cout << "a = " << a << endl;}void test(){    int a = 4;    referen(a);}

例子2.

void referen2(const int &a)  //const int cont * a{    cout << "a = " << a << endl;}void test03(){    referen2(8);}
3,函数重载

函数重载碰到默认参数:注意避免二义性

例子:

void overload(){    cout << "overload()" << endl;}void overload(int a){    cout << "overload(int a)" << endl;}void overload(int a, int b = 9090){    cout << "overload(int a, int b = 9090)" << endl;}/*void overload(int a, int b){    cout << "overload(int a, int b)" << endl;}*/int main(void){    //overload(4);  //err他不知道选择那个一个     overload(); //ok    overload(5, 9); ok    system("pause");    return 0;}

4,extern “C”的使用

方法1:extern "C" void show(); //声明C函数方法2:#ifndef __cpluscplusextern "C" {#endif // !__cpluscplus } #ifndef __cplusplus #endif // !__cplusplus

5,函数封装

  1. 将属性和行为作为一个整体了表现在生活的数据
  2. 加权限 public, protected, private
  3. C++中struct与class的区别是权限的不同, struct结构体默认是public的,class默认是private属性

6,C的宏定义和C++加强内联函数inline的区别

#define SUM(a , b) (a + b);#define MAX(a, b) (a > b ? a : b)int main(void){    int a = 90, b = 3;    SUM(++a, b); // (++a + b);    MAX(++a, b); //(++a > b ? ++a : b) //区别     return 0;}

使用内联函数inline就不会出现++a的现象

define SUM(a , b) (a + b);

define MAX(a, b) (a > b ? a : b)

int main(void)
{
int a = 90, b = 3;
SUM(++a, b); // (++a + b);
MAX(++a, b); //(++a > b ? ++a : b) // 区别
return 0;
}

使用内联函数inline就不会出现++a的现象
三,类的深拷贝浅拷贝问题 explicit(隐式法 )的使用

1,类的构造函数和析构函数的虚函数的表示
1. 括号法 (类名 别名(参数))
2. 显示法 (类名 别名 = 类名(参数))

3. 隐式法 (类名 别名 = 参数)
4. 赋值的是的const使用 void* getname() const;

2,拷贝函数的使用场景
1. 创建一个类的时候使用拷贝函数
2. 值传递方式会调用拷贝函数
3. 以返回值类 方式调用拷贝函数

include “../include/Game.h”

Game::Game()
{
cout << “Game 无参构造函数” << endl;
}
void Game::setG(char* name)
{
g_name = name;
}
char* Game::getG() const
{
return g_name;
}
Game::Game(const Game& g)
{
cout << “Game 拷贝构造函数” << endl;
g_name = (char*)malloc(sizeof(g.getG()) + 1);
memset(g_name, 0, sizeof(g.getG()) + 1);
strcpy(g_name, g.getG());
}
Game::~Game()
{
cout << “Game 析构函数” << endl;
// 释放内存
/*if (g_name != NULL)
free(g_name);
g_name = NULL;*/
}

Phone

include “../include/Phone.h”

void Phone::setp(char* name)
{
p_name = name;

}
char* Phone::getP()const
{
return p_name;
}
Phone::Phone()
{
cout << “Phone 无参数构造函数” << endl;
}
Phone::Phone(const Phone& p)
{
cout << “Phone 拷贝构造函数” << endl;
p_name = (char*)malloc(sizeof(p.getP()) + 1);
memset(p_name, 0, sizeof(p.getP()) + 1);
strcpy(p_name, p.getP());
}
Phone::~Phone()
{
cout << “Phone 析构函数” << endl;
/*if (p_name != NULL)
free(p_name);
p_name = NULL;*/
}

Person

include “../include/Person.h”

void Person::setName(char* name)
{
m_name = name;
}
char* Person::getName() const
{
return m_name;
}
void Person::setPhone(Phone& p)
{
m_phone = p;
}
Phone Person::getPhone() const
{
return m_phone;
}
void Person::setGame(Game& g)

{
m_game = g;
}
Game Person::getGame() const
{
return m_game;
}
Person::Person()
{
cout << “Person 无参构造函数” << endl;
}
Person::Person(const Person& p)
{
cout << “Person 拷贝构造函数” << endl;
m_name = (char*)malloc(sizeof(p.getName()) + 1);
strcpy(m_name, p.getName());
m_phone = p.getPhone();
m_game = p.getGame();
}
void Person::isplay()
{
cout << m_name << m_phone.getP() << m_game.getG() << endl;
}
Person::~Person()
{
cout << “Person 析构函数” << endl;
/*if (m_name != NULL)
free(m_name);
m_name = NULL;*/
}

test

include “../include/Phone.h”

include “../include/Game.h”

include “../include/Person.h”

void test()
{
Person p;
p.setName(“chen”);
Phone p2;
p2.setp(” 小米”);

Game g;
g.setG(” 王者荣耀”);
p.setPhone(p2);
p.setGame(g);
p.isplay();
}

int main(void)
{
test();
system(“pause”);
return 0;
}
效果图

深拷贝构造函数使用的时自己要添加 , 不是可以不用写了,编译器已经把写好了

3.explicit隐式法的使用 ,Google推荐使用隐式法的
Google禁止使用隐式法
class Person
{
private:
int m_a;
public:
Person(int a){ this->m_a = a};
};

void test01()
{
Person p = 1; //google 禁止使用隐式法的这样后期维护难
}

Google推荐explicit
class Person
{
private:
int m_a;
public:
explicit Person(int a){ this->m_a = a};
};
void test01()
{
//Person p = 1; //err
Person p(1);
}

//Google 推荐的

4.new, delete
①, malloc 计算分配多少内存要判断是否分配成功
② malloc 不会调用构造函数 而 new会调用构造函数
③ free 不会调用析构函数 delete 会调用析构函数
④ malloc 和 free 配套使用 ,他们都属于库函数
⑤ new 和 delete 配套使用 ,他们属于运算符
⑥ malloc 返回的是 void* 需要强制类型转换 ,而 new返回是该对象的指针,不需要类型转

⑦不要用 void* 接受 new出来的对象,原因是无法进行释放
⑧利用 new创建数组 delete 时候 要加【】 delete [] 数组名

四,引用作为返回值的

  1. 返回引用的函数实际上是被引用的变量的别名
    1,在作为函数参数和函数的返回值的引用

    free_throws & accmulate(free_throws & target,
    const free_throws & source)
    {
    target.attempts += source.attempts;
    target.made += source.made;
    set_pc(target);
    return target;
    }
    函数accmulate使用有好几种

1.
2.
3.
4.
5.

accmulate(team, one); display(team);
display(accmulate(team, two));
accmulate(accmulate(team, three), four);
dup = accmulate(team, five);
accmulate(dup, five) = team;

2,将 const用于引用返回类型
const free_throws & accmulate(free_throws & target,
const free_throws & source);
那么函数的一些的调用就不可以使用了

  1. accmulate(accmulate(team, three), four);
  2. accmulate(dup, five) = team;

3,将引用用于类对象

string version1(const string & s1,
const string & s2)
{
string temp;
temp = s2 + s1 + s2;
return temp;
}
const string & version2(string & s1,
const string & s2)
{
s1 = s2 + s1 + s2;
return s1;
}
const string & version3(string & s1,
const string & s2)
{
string temp;
temp = s2 + s1 + s2;
return temp;
/*s1 = s2 + s1 + s2;
return s1;*/
}
测试test
void test01()
{
string input;
string copy;
string result;
cout << “Enter a string: “;
getline(cin, input);
copy = input;
cout << “Your string as entered: ” << input << endl;
result = version1(input, “*“);
cout << “Your string enhanced: ” << result << endl;
cout << “Your string enhanced: ” << result << endl;
cout << “Your original-string:” << input << endl;
result = version2(input, “###”);
cout << “Your string enhanced: ” << result << endl;

cout << “Your original string: ” << input << endl;
cout << “Resetting original string: \n”;
input = copy;
result = version3(input, “@@@”); //err
cout << “Your string enhanced: ” << result << endl;
cout << “Your original string: ” << input << endl;
}

4,何时使用引用参数
使用引用参数的主要原因有两个

  1. 程序员能够修改调用函数中的数据对象。
  2. 通过传递引用而不是整个数据对象,可以提高程序的运行速度。
    当数据对象较大时(如结构和类对象),第二个原因最重要。这些也是使用指针参数的原因。
    这是有道理的,因为引用参数实际上是基于指针的代码的另一个接口。那么,什么时候应
    使用引用,什么时候使用指针呢?什么时候应按值传递呢?下面是一些指导原则:
    一,对于使用传递的值而不作修改的函数

  3. 如果数据对象很小,如内置数据类型或小型结构,可以按值传递。

  4. 如果数据对象是数组,值使用指针,因为这是唯一的选择,并将指针声明为指向const的指
    针。

  5. 如果数据对象是较大的结构,使用const指针或者const引用,以提高程序的效率。这样可以
    节省复制结构所需的时间和空间。

  6. 如果数据对象是类对象,使用const引用。类设计的语义常常要 求使用引用,这是C++新增
    这项的主要原因。因此,传递类对象参数的标准分数是按引用传递。
    二,对于修改调用函数中数据的函数

  7. 如果数据对象是内置数据类型,则使用指针。如果看到诸如fixit(&x)这样的代码(其中x是

    int),则很明显,该函数将修改x。

  8. 如果数据对象是数组,则只能使用指针。
  9. 如果数据对象是结构,则使用引用或指针。
  10. 如果数据对象是类对象,则使用引用。

五,静态,常量,单例模式, this指针和有元

1,静态和常量的关系总结
①静态常量和静态函数的关系

1.
2.
3.
4.

静态常量必须在类的外面赋值
静态常量在程序编译阶段就已经赋值了
静态常量是静态函数来管理的和改变只,类中函数改变只是静态常量一个临时的值
静态函数是全局的可以访问的

②常量和常量函数的关系

  1. 常量在格式是const int 数据类型;
  2. 常量不可以是不可以修改的,但是要修改可以在声明的时候加上

mutable关键字 是可

修改的

  1. 常函数的格式是 返回值 方法名(参数) const; 的格式
  2. 常函数不可以修改内容的只可以读的工作的有一个例外加上 mutable的变量
  3. 常类只可以访问常函数的因为常类可以修改内容的
    ③静态和常量总结

2,单例模式
说明:单例模式是只有一个实例,所有的其他的都是用同一实例就叫单例模式,而且这个实例当
程序运行起来时存在直到程序结束

define _CRT_SECURE_NO_WARNINGS

include

include

using namespace std; // 使用
标准的命名空间
class Printer
{
private:
int sum;
static Printer* singlePrinter;
Printer()
{

cout << ” 无参构造函数” << endl;
sum = 0;
}
// 拷贝函数的
Printer(const Printer& p)
{
cout << ” 拷贝构造函数” << endl;
}
public:
// 得到实例
static Printer* getInstanect()
{
return singlePrinter;
}
void getShowTest(string name)
{
cout << name << endl;
sum = 1 + sum;
cout << sum << endl;
}
~Printer()
{
cout << ” 析构函数” << endl;
}

};
// 实例化
Printer* Printer::singlePrinter = new Printer;

void test01()
{
Printer* p1 = Printer::getInstanect();
p1->getShowTest(” 陈丽”);
p1->getShowTest(” 王蓉”);
Printer* p2 = Printer::getInstanect();
p2->getShowTest(” 王盼盼”);
if (p1 == p2)
cout << ” 相同” << endl;
else
cout << ” 不相同” << endl;
}
int main(void)

{
test01();
system(“pause”);
return 0;
}

3,*this指针的使用
Person& getAdd(int age)
{
this->setAge(this->m_age + age);
return *this;
}

4,有元函数和有元类
声明的格式分别是

  1. 有元函数: friend 返回类型 方法名 (参数);
  2. 有元类: friend class 类名;
  3. 有元类中有元函数:friend 作用域::方法名(参数);
    class Person
    {
    friend void test();
    private:
    int m_a;
    char* che;
    };
    void test()
    {
    Person p;
    p.m_a = 90;// 可以访问,赋值操作
    cout << p.m_a << endl;
    }

六,数组类的封装,运算符重载和智能 this指针的使用

1,数组类的封装

UML的结构图
文件的声明:
class MyArray
{
public:
/* 数组类的拷贝构造函数 */
MyArray(const MyArray&arr);
/* 数组类的有参构造函数参构造函数 */
MyArray(int capactity);
/* 数组类的析构函数 */
~MyArray();
/* 数组类的无参构造函数 */
void Myarray(void);
/* 在数组的尾巴插入数据val */
void Tail_pash(int val);
/* 按照位置index 位置改变数组的index 位置的值 */
void set_arr_val(int index, int val);
/* 获取数组index 值 */
int getValData(int index);
/* [] 运算符重载 index */
Myarray& operator[](int index);
/* 获取数组类的长度 */
int getLength(void);
protected:
private:
/* 数组的已经有的数据大小size */
int m_Size;
/* 数组类的首地址 */
int* m_Address;
/* 数组类的容量大 */
int m_Capatity;
};

2,运算符重载
① ++,–运算符重载
我发现一个问题就是引用作为返回值时在 gcc上是报错的
前置++,–的格式
对象名& operator++()

{
this-> 变量++ ;
return *this;
}
后置++,–的格式是要找到一个中间变量
对象名 operator++(int)

{
对象名 temp;

temp. 变量 = this-> 变量;
this-> 变量++;
return temp;
}
② <<,>>运算符操作
一般使用全局函数作为<<,>> 要声明成有元函数
格式:friend ostream& operator<<(ostream& os, 对象名& p);

操作:
ostream& operator<<(ostream& os, 对象名& p)
{
os << p. 变量 ;
return os;
}

3,智能指针 this的使用

UML图
头文件声明: pointer
class Pointer
{
public:
/* Pointer 无参构造函数 */
Pointer();
/* 显示变量m_a */
void getShow(void);
/* Pointer 析构函数的使用 */
~Pointer();
protected:
private:
/* 常量m_a */
int m_a;

};

SmartPointer.h

include

if !defined(__MyString_MyString_h)

define __MyString_MyString_h

class MyString
{
public:
/* 有参构造函数 */
MyString(const char* str);
/* Mystring 类的拷贝函数
* 深拷贝字符串char* */
MyString(const MyStirng&* my_str);
/* 析构函数 释放内存 */
~MyString();
/* 分为两种情况赋值操作
* 1 ,char* 类型
* 2 ,对象 类型的赋值操作 */
MyString& operator=(char* str);
/* 对象赋值的操作 */
MyString& operator=(const MyString& my_str);
/* 取出字符串中的index 的字符的操作 */
char operator[](const int index);
/* 字符串拼接的也两种情况
* 1 ,char* 拼接
* 2 ,对象类型拼接 */
MyString operator+(const char* str);
/* 字符串拼接
* 对象拼接的情况 */
MyString operator+(const MyString& my_str);
/* 比较两个是否相同分为两种情况

* 1 ,char* 比较
* 2 ,对象 比较 */
bool operator==(const char* str);
/* 对象的比较 */
bool operator==(const MyString& my_str);
protected:
private:
/* << 运算符重载打印 */
friend ostream& operator<<(const MyString& my_str);
/* >> 赋值的操作的 */
friend istream& operator>>(const MyString& my_str);
/* 字符串的大小 */
int m_size;
/* 字符串的地址 */
char* m_String;

};

endif

3,继承的构造和析构, static
①先调用父类构造再调用子类构造,析构反置
②当子类成员函数和父类成员函数名相同时,子类会隐藏父类中成员函数。
解决的方法:加上作用域

4,多继承中虚继承使用,偏移量
继承中virtual相同的有在C11中以后override, final关键字了
class Animal
{
public:
int m_age;
};
class Sheep : virtual public Animal
{
};
class Tuo :virtual public Animal
{

};
class SheepTuo : public Sheep, public Tuo
{
};
void test01()
{
Sheep s;
s.m_age = 90;
s.Sheep::m_age = 100;
cout << s.m_age << endl;
}
int main(void)
{
test01();
system(“pause”);
return 0;
}
查看继承结构:
cl /d1 reportSingleClassLayout 类名

文件名.cc

八 .多态,重载,重定义,重写

1.多态的继承,虚函数
① 在父类中要把可以重写的声明成虚函数或者纯虚函数子类要重写
②析构函数在父类中要声明 virtual类型子类要重写, 当声明成纯虚析构函数是要在类父类
的外写上析构函数
class Animal
{
public:
virtual void speack() = 0; // 纯虚函数成员
virtual ~Animal() = 0; // 纯虚析构函数
/*{
cout << “Animal 析构函数” << endl;
}*/
};
Animal::~Animal()
{
cout << “Animal 析构函数” << endl;
}

③虚机类表编译器内部原理
结构图
代码:
class Animal
{
public:
int m_age;
};
class Sheep : virtual public Animal
{
int m_a;
};
class Tuo :virtual public Animal
{
};
class SheepTuo : public Sheep, public Tuo
{
};
void test01()
{
Sheep s;
s.m_age = 90;
s.Sheep::m_age = 100;
cout << s.m_age << endl;
}

4.类型转换的安全性
①向上:是子类 -> 父类 动态是安全的
②向下 :父类 -> 子类 不安全的

5.重载 (同一作用域的同名函数 ),重定义 (隐藏 ),重写 (覆盖 )
①重载

1.
2.
3.
4.

同一个作用域
参数个数,参数顺序,参数类型不同
和函数返回值,没有关系

const也可以作为重载条件 //do(const Teacher& t){} do(Teacher& t)

②重定义

1. 有继承
2. 子类(派生类)重新定义父类(基类)的同名成员(非virtual函数)

重写(覆盖)

  1. 有继承
  2. 子类(派生类)重写父类(基类)的virtual函数
  3. 函数返回值,函数名字,函数参数,必须和基类中的虚函数一致

6.接口 interface
定义:

  1. 只有纯虚函数(”=0”)和静态函数(除了下文提到的析构函数) ,析构
    函数不能是纯虚析构函数

  2. 没有非静态数据成员

  3. 没有定义任何构造函数,如果有,,也不能带有参数,并且必须为
    protected
  4. 如果它是一个子类,也只能从满足上述条件并以Interface为后缀的类继

原创粉丝点击