您的位置:首页 > 编程语言 > C语言/C++

c++ 基本语法学习

2017-04-27 13:34 465 查看
命名空间
命名空间定义方法

命名空间属性调用

案例

上述案例说明

命名空间引用冲突

命名空间嵌套

输出函数
案例

结构体
如果修饰符含有privat 不能创建

变量引用
二级指针和引用

三目运算符

指针常量和常量指针

实参形参

bool类型

字符串string

函数重载

类 class
简单创建一个类 实例化

析构函数

拷贝构造方法

拷贝函数问题

类静态属性方法初始化

在头文件中声明类和实现

直接在构造函数初始化一些数值

常函数

malloc 和new 的区别

友元函数

运算符重载

未完待续

命名空间

前言(转载自百度百科):命名空间是用来组织和重用代码的 。如同名字一样的意思,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");
}


未完待续

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: