命名空间
前言(转载自百度百科):命名空间是用来组织和重用代码的 。如同名字一样的意思,NameSpace(名字空间),之所以出来这样一个东西,是因为人类可用的单词数太少,并且不同的人写的程序不可能所有的变量都没有重名现象,对于库来说,这个问题尤其严重,如果两个人写的库文件中出现同名的变量或函数(不可避免),使用起来就有问题了。为了解决这个问题,引入了名字空间这个概念,通过使用 namespace xxx;你所使用的库函数或变量就是在该名字空间中定义的,这样一来就不会引起不必要的冲突了
命名空间定义方法:
//定义命名空间
namespace XiaoWang{
char * age="小王";
}
namespace ZhangSan{
char * age="张三";
}
命名空间属性调用:
int main(){
//引用命名空间的age变量输出 cout和endl输出方法 类似printf
cout<<ZhangSan::age<<endl;
std::cout<<XiaoWang::age<<std::endl;
return 0;
}
案例:
#include<stdio.h>
#include<iostream>
using namespace std;
//定义命名空间
namespace XiaoWang{
char * age="小王";
}
namespace ZhangSan{
char * age="张三";
}
int main(){
//引用命名空间的age变量输出
cout<<ZhangSan::age<<endl;
std::cout<<XiaoWang::age<<std::endl;
return 0;
}
结果 :
张三
小王
上述案例说明
using namespace std; 再此声明以后的函数使用命名空间std
此声明是用于 cout函数
我们删除上面这句话的看看
解决办法1:
在开头声明using namespace std;解决办法2:
在函数前添加命名空间
int main(){ //引用命名空间的age变量输出 std::cout<<ZhangSan::age<<std::endl; std::cout<<XiaoWang::age<<std::endl; return 0; }
命名空间引用冲突
当你引用了两个命名空间,而两个空间都有age这个属性时,需要手动在函数前指明
命名空间嵌套:
/*
* test.cpp
*
* Created on: 2017��4��25��
* Author: FMY
*/
#include<stdio.h>
#include<iostream>
using namespace std ;
//定义命名空间
namespace A{
namespace B{
char * test ="测试";
}
}
int main(){
cout<<A::B::test<<endl;
return 0;
}
输出函数
c语言输出函数printf 对应c++的cout函数
1. cout 函数 位于iostream下
2. 命名空间std
3. 输出方式:
1. std::cout<< 输出内容 ;
- 这样输出不换行
2. std::cout<< 输出内容<< endl;
- 换行输出 ,输出此语句后自动换行
3. std::cout << 输出内容1<<输出内容2 << endl << 输出内容3
- 可以继续拼接输出内容期间可以嵌套endl
案例
#include<stdio.h>
#include<iostream>
using namespace std ;
//定义命名空间
namespace XiaoWang{
char * age="小王";
}
namespace ZhangSan{
char * age="张三";
}
int main(){
using namespace ZhangSan;
//以后的代码出现age都是ZhangSan的
cout<<age<<endl;
//除非这样下
cout<<XiaoWang::age;
cout<<XiaoWang::age<<endl<<age;
return 0;
}
结果:
张三
小王小王
张三
结构体
#include<stdio.h>
#include<iostream>
using namespace std ;
struct person{
//如果不写访问修饰符默认为 public
public:
char name [20];
int age;
public:
int weight;
void (*eat)(char * food);
};
void eat2(char *food){
cout<<"我在吃"<<food<<endl;
}
int main(){
//不需要写 struct 并且增加访问符号
person p{"asd",1,1,eat2};
p.eat("asd");
return 0;
}
如果修饰符含有privat 不能{}创建
变量引用
前言:就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。(次句话转自某博文)
#include<iostream>
using namespace std;
struct MyStruct
{
char *name;
};
int main(){
int a = 1;
int b = 27;
//给a变量取别名c
//修改c变量会直接修改a变量
int &c = a;
//此时a也会变成23
c = 23;
MyStruct p1{ "阿斯顿" };
//给p取别名
MyStruct &p2 = p1;
//此时 p.name也会变
p2.name = "爱迪生";
cout << a<<endl;
cout << p2.name;
getchar();
return 0;
}
输出:
23
爱迪生
#include<iostream>
using namespace std;
struct MyStruct
{
char *name;
};
//返回同一个引用 由于是static 修饰 所以访问的是同一个
int & test(){
//静态修饰的只会第一次调用的时候执行a = 23
static int a = 23;
return ++a;
}
//每次从栈返回 一个引用 不推荐
int& test2(){
int a = 222;
return ++a;
}
int main(){
cout << test() << endl;
cout << test() << endl;
int c = test2();
cout << test2() << endl;
cout << test2() << endl;
getchar();
return 0;
}
输出
24
25
223
223
二级指针和引用
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
using namespace std ;
struct Man{
char*name;
};
int main(){
Man *m1 = (Man*) calloc(sizeof(Man),1);
m1->name ="你好兄弟";
Man ** m2 = (Man**) calloc(sizeof(Man*),1);;
m2 = &m1;
cout<<"一级指针"<<m1->name<<endl;
cout<<"二级指针"<<(*m2)->name<<endl;
//-----------------引用和二级指针-----------------------
Man *aaa = (Man*) calloc(sizeof(Man),1);
//以下这种方法是错误,因为我们说过引用是取别名 ,你没有原本的名字变量 怎么取别名?
//Man &aaa = (Man*) calloc(sizeof(Man),1);
Man* &mm1 = aaa;
mm1->name = "嘿嘿";
cout<<"二级引用"<<mm1->name<<endl;
return 0;
}
三目运算符
前言:
在c++中三目的的结果可以作为 表达式左值
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std ;
int main(){
int a = 1;
int b = 2;
*((a>b)?&a:&b) = 232;
cout<<b<<endl;
return 0;
}
结果:232
指针常量和常量指针
实参形参
在 java方法中传入一个对象 ,在方法中修改对象会直接影响实参 .
c++ 中除非运用指针,或者引用 .不然不会引起实参变化
/*
* test.cpp
*
* Created on: 2017��4��25��
* Author: FMY
*/
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std ;
struct Man{
char *name;
};
//传入的时候把实参拷贝一份在方法栈区
void test( Man p){
//此时修改并不影响调用方法的实参
p.name ="修改";
}
int main(){
Man man {"旧的"};
//传入的时候把实参拷贝一份在方法栈区
test(man);
cout<<man.name<<endl;
return 0;
}
结果:旧的
bool类型
/*
* test.cpp
*
* Created on: 2017��4��25��
* Author: FMY
*/
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std ;
int main(){
bool flag = true;
// bool flag = 1;//这里也是可以赋值数值类型的
if(flag){
cout<<"真的"<<endl;
}else{
cout<<"假的"<<endl;
}
cout<<"bool所占用字节数"<<sizeof(bool)<<endl;
return 0;
}
结果:
真的
bool所占用字节数1
字符串string
因为string的使用和java差不多所以这里不打算说太多
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
using namespace std ;
int main(){
string testString = "hello world";
cout<<"输出字符串"<<testString<<endl;
cout<<"输出字符串 长度"<<testString.length()<<endl;
//转化为char*
const char * convertChar = testString.c_str();
cout<<"转换为char* "<< convertChar<<endl;
return 0;
}
输出
输出字符串hello world
输出字符串 长度11
转换为char* hello world
函数重载
我们在java的时候调用方法是支持重载的,可以根据实参传入的类型和个数位置不同确定调用哪一个方法
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
using namespace std ;
void my(char * name){
cout<<"my(char * name) ----"<<name<<endl;
}
void my(int name){
cout<<"my(int * name) ----"<<name<<endl;
}
int main(){
//根据传入的参数类型和个数确定调用哪个类型
my("sd");
my(1);
return 0;
}
类 class
简单创建一个类 实例化
new的对象需要用delete删除堆内存
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std ;
class man{
public :
char * name ;
//构造方法
man(char *name){
cout<<"构造方法"<<endl;
this->name =name;
}
};
int main(){
//这种创建方式会 在栈中创建 ,对象可控性不强
man a("Asd");
//和上面的一样
man b = man ("Asd");
//如果使用new的方式 需要 delete删除,因为new是从堆创建的所以和malloc
man * c = new man ("new 创建");
//从堆中删除c
delete c;
return 0;
}
输出:
构造方法
构造方法
构造方法
析构函数
在对象被回收的时候调用的时候回调的方法
在c++中析构函数为 ~对象名字()
tip:在java中析构函数名字finalize()
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std ;
class man{
public :
char * name ;
~man(){
cout<<"析构函数" <<this<<endl;
}
};
int main(){
man *a=new man ();
delete a;
return 0;
}
输出
析构函数0x1f1f60
拷贝构造方法
应用场景 对象 A = 对象B
此时会回调对象拷贝构造方法
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std ;
class man{
public :
char * name ;
man(char * name){
this->name = name;
}
};
int main(){
man * a=new man ("a");
man b = *a;
b.name= "b";
cout<<a->name<<endl;
return 0;
}
输出:
a
这里学java的同学转c++可能不理解,这里man b = *a; 是将对象a中数值拷贝一份创建一个备份生成,两者互不联系
上面的拷贝拷贝函数没有写 ,是因为系统默认帮我们写了.实际中默认写法如下
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std ;
class man{
public :
char * name ;
man(char * name){
this->name = name;
}
//默认拷贝方法 ----值拷贝 浅拷贝
man(const man& p){
this->name = p.name;
}
};
int main(){
man * a=new man ("a");
man b = *a;
b.name= "b";
cout<<a->name<<endl;
return 0;
}
拷贝函数问题
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std ;
class Man{
public:
char *name;
public:
Man(char *name){
this->name = (char*)malloc(100);
strcpy(this->name,name);
cout << "构造函数" << endl;
}
~Man(){
//释放内存
free(this->name);
cout << "析构函数" << endl;
}
void myprint(){
cout << name << endl;
}
};
void func(){
Man m1((char*)"fmy");
Man m2 = m1;
strcpy(m1.name,"asd");
m2.myprint();
}
int main(){
func();
return 0;
}
上面的代码会在某些编译器运行奔溃:
原因:man类对象中name进行拷贝的时候是直接将指针赋值另一个对象,导致两个对象共用一个,当其中一个销毁的时候,因为name也会被销毁.可是他们共用引起了野指针
解决办法:用深度拷贝
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std;
class Man{
public:
char *name;
public:
Man(char *name){
this->name = (char*)malloc(100);
strcpy(this->name, name);
cout << "构造函数" << endl;
}
~Man(){
//释放内存
free(this->name);
cout << "析构函数" << endl;
}
Man(const Man& m){
this->name = (char *)malloc(sizeof(char)* 111);
strcpy(this->name, m.name);
}
void myprint(){
cout << name << endl;
}
};
void func(){
Man m1((char*)"fmy");
Man m2 = m1;
strcpy(m1.name, "asd");
m2.myprint();
}
int main(){
func();
getchar();
return 0;
}
类静态属性方法初始化
- 案例1.初始化静态变量
可以看到上面报错了.那么到底怎么初始化变量呢?
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std ;
class Man{
public :
static int a ;
};
int Man::a =22;
int main(){
cout<<Man::a<<endl;
Man::a =2;
cout<<Man::a<<endl;
Man s();
return 0;
}
输出
22
2
- 案例2静态方法
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std ;
class Man{
public :
static void aa(){
cout<<"静态方法aa"<<endl;
}
static void bb();
};
void Man::bb(){
cout<<"bb方法"<<endl;
}
int main(){
Man::aa();
Man::bb();
return 0;
}
输出:
静态方法aa
bb方法
在头文件中声明类和实现
先看test.h
class man{
public:
char *name;
void eat();
};
再看看实现类
test.cpp
发现用 xxx ();初始化的一个变量的时候无法调用内部方法
- 解决办法1:
改用new 或者malloc
int main(){
man* m =new man();
m->eat();
m->name = "你好吗?";
getchar();
return 0;
}
- 解决办法2:
创建一个传入参数不是空的构造方法
class man{
public:
char *name;
void eat();
man(int a){
}
};
#include<iostream>
#include"test.h"
using namespace std;
void man::eat(){
cout << "asd" << endl;
};
int main(){
man a(1);
a.name = "asd";
getchar();
return 0;
}
直接在构造函数初始化一些数值
常函数
malloc 和new 的区别
malloc 创建的对象也会在堆中,但是不会调用class 的构造方法.和构造方法(一般情况下不会,除非你用指针把对象拷贝),其他方式都会调用如 xx(),new xx().
案例1:
class man{ public : char * name ; //构造方法 man(char *name){ cout<<"构造方法被调用咯 传入的name===" <<name<<endl; this->name =name; } man(const man& m){ cout<<"拷贝方法"<<endl; this->name = m.name; } ~man(){ cout<<"析构函数"<<endl; } }; int main(){ man *m = (man* ) malloc(sizeof(man)); free(m); return 0; }
输出:无输出
案例2
#include<stdio.h> #include<iostream> #include<string.h> #include<stdlib.h> #include <stdio.h> #include <stdarg.h> using namespace std ; class man{ public : char * name ; //构造方法 man(char *name){ cout<<"构造方法被调用咯 传入的name===" <<name<<endl; this->name =name; } man(const man& m){ cout<<"拷贝方法" <<this<<endl; this->name = m.name; } ~man(){ cout<<"析构函数" <<this<<endl; } }; int main(){ man *m = (man* ) malloc(sizeof(man)); cout<<"指针m保存的地址"<<m<<endl; m->name = "嘿嘿"; //将指针保存的内容拷贝到别处man对象上 ,触发拷贝发生 在对象回收后触发析构函数 在栈区创建的对象m2 man m2 = *m; cout<<"m2的地址"<<&m2<<endl; //用此方法可以回收 m内存 并且回调析构函数 delete m; return 0; }
输出:
指针m保存的地址0x6e1f60
拷贝方法0x61ff18
m2的地址0x61ff18
析构函数0x6e1f60
析构函数0x61ff18
友元函数
当一个类中有私有变量的时候,正常是无法通过xxx.yy去访问的,只能通过函数间接访问.
正常访问私有变量:
友元函数访问私有
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std ;
#include"test.h"
class woman {
friend void accessmy(woman *p);
public:
int age;
char *name;
private:
//私有变量
int weight;
void eat(){
cout<<"私有方法eat"<<endl;
}
};
void accessmy(woman *p){
cout<<"访问"<<p->weight<<endl;
}
int main(){
woman* m = new woman();
accessmy(m);
return 0;
}
- 案例2
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std ;
#include"test.h"
class woman {
friend class B;
public:
int age;
char *name;
private:
//私有变量
int weight;
void eat(){
cout<<"私有方法eat"<<endl;
}
};
class B{
public :
void accessmy(){
//随便访问
w.weight =30;
}
private:
woman w;
};
运算符重载
我们在使用java的String类型可以用”+”号拼接两个字符串,c++当然也可以.在我们一开始使用cout函数”<<”符号的时候 大家有没有想过他们是怎么做到的?
案例1:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std ;
#include"test.h"
class Point{
public:
int x;
int y;
Point(int x,int y):x(x),y(y){
}
};
Point operator+(const Point &p1, const Point & p2 ){
return Point (p1.x+p2.x,p1.y+p2.y);
}
int main(){
Point p1(1,3);
Point p2(2,4);
Point p3 = p1+p2;
cout<<"("<<p3.x<<","<<p3.y<<")"<<endl;
return 0;
}
案例2
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdarg.h>
using namespace std ;
#include"test.h"
class Point{
public:
int x;
int y;
Point(int x,int y):x(x),y(y){
}
Point operator+( Point & p2 ){
return Point (this->x+p2.x,this->y+p2.y);
}
};
int main(){
Point p1(1,3);
Point p2(2,4);
Point p3 = p1+p2;
cout<<"("<<p3.x<<","<<p3.y<<")"<<endl;
return 0;
}
案例3:
//当属性私有时,通过友元函数完成运算符重载
class Point{
friend Point operator+(Point &p1, Point &p2);
private:
int x;
int y;
public:
Point(int x = 0, int y = 0){
this->x = x;
this->y = y;
}
void myprint(){
cout << x << "," << y << endl;
}
};
Point operator+(Point &p1, Point &p2){
Point t(p1.x + p2.x, p1.y + p2.y);
return t;
}
void main(){
Point p1(1, 3);
Point p2(2, 4);
//运算符的重载,本质还是函数调用
//p1.operator+(p2)
Point p3 = p1 + p2;
system("pause");
}