目 录
1 开始学习C++
1.1 C++的头文件
1.2 命名空间
1.3 更严格的类型转化
1.4 new和delete
1.5 内联函数
1.6 引用
1.7 函数的重载
2 类和对象
2.1 C++类成员的保护
2.2 C++类的本质
2.3 类的作用域
2.4 类的构造和析构函数
2.5 构造函数的初始化成员列表
2.5.1 原则:
2.6 拷贝构造函数
2.6.1 浅拷贝
2.6.2 深拷贝
2.6.3 原则:
2.7 常量类成员,常量对象,类对象做函数形参。
2.8 explicit
2.9 this指针
类的static成员变量
开始学习C++
C++的头文件
传统的C头文件<stdio.h>。
C++头文件#include<iostream>
hpp头文件
C++引入了新的概念,命名空间可以有效避免大型项目中的各种名称冲突usingnamespace std;
namespace na
{
int a;
char c;
}
na::a = 1;
class关键字
class是C++的核心,是面向对象编程的核心内容
在C++,不同类型的指针是不能直接赋值的,必须强转
new和delete
new和delete是C++内建的操作符,不需要有任何头文件,用new分配的内存必须用delete释放,不要用free。malloc则需要头文件malloc.h
new创建数组的方法int *arr=new int[n]; delete []arr;
inline关键字的意思是,内联函数不作为函数调用,而是直接把内联函数的代码嵌入到调用的语句中,在调用的地方直接展开,不用函数的入栈和出栈
内联函数适合函数代码很少,并且频繁的大量调用。
inlinevoid Foo(int x, int y); // inline仅与函数声明放在一起
void Foo(int x, int y)
{
}
引用就是一个变量的别名,而不是地址 int a ; int &b=a; a和b完全等价
函数的缺省参数
C++允许函数在定义的时候,提供缺省参数,如果调用函数的时候没有提供形参,那么形参的值就是缺省值
引用做为函数的参数,没有出栈,入栈操作,是直接操作原变量,所以效率更高int & a
如果要使引用参数的值不能在函数内部被修改,那么就定义为常量引用 const int& a
函数的名称是一样的,但参数不同可以重载
函数参数相同,但返回值不同,不可以重载,不可以通过返回值不同来重载
模版函数
template <class T >
T myadd(T a,T b)
{ return a+b;}
C++类成员的保护
如果类函数返回的是成员变量的指针,为了避免在类外部成员变量被修改,所以函数就要返回常量指针如constchar *
如果一个类成员变量和一个全局变量重名,那么在类成员函数当中默认访问的是类的成员变量.
在类的内部访问全局标识,关键字::全局变量
如类中使用::age=”tom” age是全局变量
C++类的本质
类其实就是结构的数据成员加可执行代码,统一提供封装,继承,多态。
struct str{
int a;
}
class cla
{
int a;
set_name(int tem)
{
a=tem;
}
}
sizeof(struct str)=sizeof(cla) 结构体大小和类大小相等
在类内部,没有权限限定符,默认是private
在结构内部,没有权限限定符,默认是public
类成成员变量作用域局限于类内部,类的外部是不可见。
构造函数名称和类的名称一致,而且没有返回值
一个类实例化为一个对象的时候,自动调用。
一个对象在销毁的时候会自动调用析构函数。
初始化成员列表只能在构造函数使用
类中const成员变量必须用初始化成员列表赋值
引用数据成员必须用初始化成员列表赋值
MyClass(intx):a(0),b(0),max(x)
{
}
由于析构函数只有一个,所以在不同的构造函数里面给函数的成员指针分配内存的时候,一定要统一在同一个构造函数里new或者new[],
demo()
{
int *p1 = new int[5];
}
demo(int i)
{
int *p2 = new int[4];
}
~demo()
{
析构里不知道到底要释放p1还是p2内存,你可能调用有参或无参的构造,
}
classman
{
char *name;
};
man ma1;
manman2 = man1;调用了拷贝构造函数,类似于c语言中的结构体赋值
浅拷贝(默认的拷贝构造函数,如果你没有实现拷贝构造函数,编译器自动实现的拷贝构造函数)
两个对象之间成员变量简单的赋值,类似于c语言中的结构体赋值。默认的浅拷贝构造函数只是仅仅将对象里的指针变量进行拷贝复制,不会将对象里的指针变量指向的内存拷贝一次。
深拷贝(自己实现的拷贝构造函数)
不同的对象指针成员指向不同的内存地址,拷贝构造的时候不是简单的指针赋值,而是将内存拷贝过来,自己实现拷贝构造后所有的对象成员变量的复制都需要自己手动实现。
man::man()
{
name = new char[10];
}
man::man(constman& it)
{
name = new char[10];
strcpy(name, it.name);
}
如果类成员有指针,那么需要自己实现拷贝构造函数,不然存在浅拷贝的风险,如果一个函数里参数是对象,那么就会调用默认拷贝构造函数,如果你自己实现了拷贝构造函数则会调用自己实现的拷贝构造函数,所以一般函数的参数用引用传对象,效率就会提高。
test(man & ma)或者test(const man & ma)
常量_类成员:类成员后面跟关键字const意思是告诉编译器,这个函数内部不会对类成员变量做任何修改
constchar * man::get_name() const{
return name;
}
常量对象:const man m; m是一个常量对象,初始化后以后都不能修改这个对象的成员变量,类中的成员变量都变成const类型了
函数的参数如果是一个类对象,那么就用类对象的引用,效率更高!
void test(manm&){ cout << m.name; }
如果不想参数被调用函数内部修改,那么就采用const&
void test(constman m&){ cout << m.name; }
void test(constman m){ cout << m.name; } //这种方法拷贝效率超低
告诉C++编译器,要明确的调用这个构造函数I处,而不要编译器自作聪明的认为=操作符是要调用构造函数II处。
classman{
private :
char * name;
public:
explicit man (const char *name){ neme = name;}
}
调用man m =“ouyang”;//错误!=不能调用构造,必须写成下面的格式II处
man m2(“ouyang”); //正确 I处
classman{
private :
char * name;
public:
man (const char *name){ neme = name;}
}
man m =“ouyang”; //正确,编译器的智能认为你是想调用man (const char *name)这个构造函数,但有时候=我们会重载运算符
manm2(“ouyang”); //正确
this指针
this就是指向自己实例的指针
类的static成员变量(只需要声明时指明静态,定义和使用不需要static关键字)
static变量是放到静态内存区的,程序加载就存在,一直到程序退出才清理。
类的static成员和类的对象没有直接关系,类的静态成员是放到静态内存区的,程序开始执行就存在,一直到程序结束才清理。
类的静态成员变量不论类的实例有多少,但成员变量只有一份。
class man{
private :
char* name;
public:
static int count;
explicit man (const char*name){ neme = name;}
static void set_count(int i);
static int get_count();
static void test(man ma);
}
//类的静态函数不能访问类的非静态成员变量,因为在调用类的静态函数或类的静态成员变量时,类可能还没有实例化,此时调用会出错,
但是类的静态成员函数内可以通过类对象间接访问类的非静态成员函数
void man::set_count(int i)
{
count = i;
}
int man::get_count()
{
return count;
}
static void test(man ma)
{ //因为ma对象已经实例化了,所以可以调用实例化对象ma的成员变量
cout << ma.name;//通过类间接使用非静态数据成员,而且可以是私有的
}
int main()
{
man::count = 200;
man::set_count(200);
}
//类的静态成员初始化,只是挂到这个类名下,因为c++不喜欢全局变量,就算没有实例化man对象,也可以照常使用静态变量count,唯一的区别是可以在类中对这个静态成员变量加访问权限限定符public,private