您的位置:首页 > 财经 > 产业 > 龙岩网站建设方式_python网页制作项目_seo网络营销技巧_论文收录网站排名

龙岩网站建设方式_python网页制作项目_seo网络营销技巧_论文收录网站排名

2024/12/22 20:58:24 来源:https://blog.csdn.net/gma999/article/details/143387582  浏览:    关键词:龙岩网站建设方式_python网页制作项目_seo网络营销技巧_论文收录网站排名
龙岩网站建设方式_python网页制作项目_seo网络营销技巧_论文收录网站排名

1. 成员变量声明为Private

建议将成员变量声明为Private,然后再public中提供调用该数据的接口

设置成Private的原因分析

  • 类内成员变量被声明为Private,那么就可以外部代码直接访问或者修改内部数据
  • 通过公共接口获取内部数据,这样可以减少对外部代码的影响
  • 直接将成员变量设置为public,可能会导致数据不一致或者逻辑错误,将成员变量设置为Private就可以避免外界随意修改数据,从而确保数据的完整性

将成员变量设置为public错误事例分析 

外部代码可以随意修改变量的数值,与此同时还可以将其设置负数 

#include <iostream>
#include <string>class Person {
public:std::string name;  int age;           
};int main() {Person p;p.name = "Alice";p.age = -5;  std::cout << "名字:" << p.name << ",年龄:" << p.age << std::endl;return 0;
}

 解决方法:成员变量声明为Private,同时提供公共接口

  • 获取成员变量只可以通过getter方法访问
  • 设置成员变量则是通过setAge,该方法内部会检查数据的有效性

#include <iostream>
#include <string>class Person {
public:Person(const std::string& name, int age) : name_(name) {setAge(age);  // 使用 setter 进行初始化}// Getterstd::string getName() const { return name_; }int getAge() const { return age_; }// Settervoid setAge(int age) {if (age >= 0) {  // 检查年龄有效性age_ = age;}else {std::cerr << "错误:年龄不能为负数" << std::endl;}}private:std::string name_;int age_;
};int main() {Person p("Alice", 25);std::cout << "名字:" << p.getName() << ",年龄:" << p.getAge() << std::endl;p.setAge(-5);  // 试图设置无效年龄std::cout << "名字:" << p.getName() << ",年龄:" << p.getAge() << std::endl;return 0;
}

成员变量声明为Private的好处

还可以支持数据验证和日志记录功能,也就是通过接口访问成员变量的时候,可以添加验证逻辑或者日志逻辑,从而更好的实现数据管理;

成员变量设置为Private后,还可以延迟初始化,避免不必要的消耗

 2. 优先使用非成员非友元函数

主要是为了减少类的复杂性,如果一个函数在实现功能的时候不需要访问类的私有成员,那么就可以将这个类设计成为非成员非友元函数

问题分析

例如在一个表示分数的类中,实现了*运算符重载,此时如果将*运算符重载成为成员函数,那么就会增加这个类的复杂性

#include <iostream>class Rational {
public:Rational(int numerator = 0, int denominator = 1): numerator_(numerator), denominator_(denominator) {}Rational operator*(const Rational& rhs) const {return Rational(numerator_ * rhs.numerator_, denominator_ * rhs.denominator_);}void print() const {std::cout << numerator_ << "/" << denominator_ << std::endl;}private:int numerator_;int denominator_;
};int main() {Rational a(1, 2);Rational b(3, 4);Rational result = a * b;result.print(); return 0;
}

解决方法:如果一个类并不需要访问私有成员(因为a,b的数值都是构造时就赋值了),此时就可以将其设计为非成员非友元函数

  • operator*定义成非成员函数,然后声明为Rational的友元,这样就可以访问其私有成员
  • 通过这样的方法简化结构的同时,还可以访问其成员 
class Rational {
public:Rational(int numerator = 0, int denominator = 1): numerator_(numerator), denominator_(denominator) {}void print() const {std::cout << numerator_ << "/" << denominator_ << std::endl;}private:int numerator_;int denominator_;// 提供访问私有成员的友元声明friend Rational operator*(const Rational& lhs, const Rational& rhs);
};// 非成员运算符重载
Rational operator*(const Rational& lhs, const Rational& rhs) {return Rational(lhs.numerator_ * rhs.numerator_, lhs.denominator_ * rhs.denominator_);
}int main() {Rational a(1, 2);Rational b(3, 4);Rational result = a * b;result.print(); return 0;
}

适合使用该方法场景分析

  • 不依赖对象内部状态的操作,例如只是数学计算、全局功能等
  • 运算符重载
  • 类中的一些辅助函数

总结反思

  • 优先使用非成员非友元函数:如果一个函数不需要访问类的私有成员,将它设计为非成员非友元函数更好
  • 减少类的复杂性:使用非成员函数可以减少类的职责和耦合度,使类的设计更清晰
  • 运算符重载优先使用非成员实现:运算符重载时,优先考虑非成员实现,除非必须访问类的私有成员
  • 提供友元函数访问私有成员:在非成员函数需要访问私有数据时,可以将其声明为友元函数

 3. 如果所有参数都需要类型转换,使用非成员函数

C++中运算符重载时,可能会需要对操作数进行隐式类型转换,当所有操作数都需要进行类型转换的时候,最好选择非成员函数实现运算符重载,因为成员函数的运算符重载只会对右侧参数进行隐式类型转换,而非成员函数则允许对所有参数进行隐式类型转换。

成员函数运算符重载限制分析

成员函数实现运算符重载的时候,隐式类型转换只会应用右侧的参数,也就是说,左侧的参数必须和对象类型匹配,否则编译器不会进行隐式类型转换

  • 下述代码编译的时候,编译器会尝试将2作为*左侧的操作数(this对象,也就是Rational类型)
  • 但是2不是Rational类型,所以最终肯定会导致编译失败

#include <iostream>class Rational {
public:Rational(int numerator = 0, int denominator = 1): numerator_(numerator), denominator_(denominator) {}// 成员函数重载运算符*Rational operator*(const Rational& rhs) const {return Rational(numerator_ * rhs.numerator_, denominator_ * rhs.denominator_);}void print() const {std::cout << numerator_ << "/" << denominator_ << std::endl;}private:int numerator_;int denominator_;
};int main() {Rational r1(1, 2);Rational result = 2 * r1;result.print();return 0;
}

解决方法:使用非成员函数运算符重载

因为非成员函数可以允许对所有参数进行隐式类型转换的,这样就可以让编译器将2隐式转换为Rational类型,从而避免了成员函数的类型限制

#include <iostream>class Rational {
public:Rational(int numerator = 0, int denominator = 1): numerator_(numerator), denominator_(denominator) {}void print() const {std::cout << numerator_ << "/" << denominator_ << std::endl;}private:int numerator_;int denominator_;// 友元声明,允许非成员函数访问私有成员friend Rational operator*(const Rational& lhs, const Rational& rhs);
};// 非成员函数重载运算符*
Rational operator*(const Rational& lhs, const Rational& rhs) {return Rational(lhs.numerator_ * rhs.numerator_, lhs.denominator_ * rhs.denominator_);
}int main() {Rational r1(1, 2);Rational result = 2 * r1;  // 允许隐式类型转换result.print();  return 0;
}

使用场景分析

  • 非成员函数运算符重载
    • 所有参数可能都需要进行隐式类型转换:例如 int * Rational,这时非成员函数更灵活
    • 对称的二元运算符:像 +-*/ 等对称运算符,通常适合实现为非成员函数
    • 允许访问私有成员:通过 friend 声明,可以让非成员函数访问类的私有数据成员,确保函数实现的灵活性
  • 成员函数运算符重载
    • 赋值相关运算符:如 =+=-=*=/=,因为它们会改变左侧操作数的值,通常应实现为成员函数
    • 单目运算符:如前置和后置 ++--、取地址 &、解引用 * 等,通常适合实现为成员函数,因为它们通常只对一个操作数进行操作

4. 实现一个不抛异常的swap函数

自我实现swap函数的原因

首先std库中提供的swap函数默认是通过拷贝构造函数和赋值运算符来实现,但是这些操作有可能会出现异常,其次主要目的就是减少性能开销,提高代码安全性

错误分析,使用默认swap交换一个有动态资源的类

  • swap使用的是拷贝构造和赋值与赋值运算符,那么就很有可能触发内存分配和释放操作
  • 代码中如果构造和赋值运算符抛出异常,那么swap就可能引发异常,最终导致w1和w2状态不一致
  • 中断原因分析:widget类中name_是一个指针类型,当使用swap交换两个widget对象中的name_指针时,一个对象被销毁后,其会释放name_指针指向的内存,而另一个对象也会释放这块已经释放的内存,所以导致了双重释放,最终导致了异常中断
    • 双重释放的根源在于,在没有定义深拷贝的时候,swap使用的是浅拷贝,所以只是简单的拷贝了其数值,所以就造成了多个对象持有相同的指针,所以最终在析构的时候就会重复释放同一块内存,最终引发异常

#include <iostream>
#include <string>
#include <algorithm>  // for std::swapclass Widget {
public:Widget(const std::string& name) : name_(new std::string(name)) {}~Widget() { delete name_; }// 打印 name_void print() const {std::cout << "Widget 名称: " << *name_ << std::endl;}private:std::string* name_;
};int main() {Widget w1("Alice");Widget w2("Bob");std::swap(w1, w2);  // 使用 std::swap,默认调用拷贝构造和赋值w1.print();w2.print();return 0;
}

解决方法:实现一个成员函数swap来直接交换数据成员,这样就可以有效避免不必要的拷贝和赋值

  • 通过交换指针,实现两个对象动态资源的交换,这样就避免了浅拷贝的问题
  • 通过非成员函数调用类中的swap函数,从而确保std::swap兼容

#include <iostream>
#include <string>
#include <utility>  // for std::swapclass Widget {
public:Widget(const std::string& name) : name_(new std::string(name)) {}~Widget() { delete name_; }// 提供一个不抛异常的 swap 成员函数void swap(Widget& other) noexcept {std::swap(name_, other.name_);  // 直接交换指针,不抛异常}// 打印 name_void print() const {std::cout << "Widget 名称: " << *name_ << std::endl;}private:std::string* name_;
};// 提供一个非成员的 swap 函数,以便与 std::swap 兼容
void swap(Widget& lhs, Widget& rhs) noexcept {lhs.swap(rhs);  // 使用 Widget 的成员 swap
}int main() {Widget w1("Alice");Widget w2("Bob");swap(w1, w2);  // 使用自定义 swap 函数w1.print();w2.print();return 0;
}

总结反思

  • 优先自己定义一个没有异常的swap函数,同时通过noexcept声明来确保swap函数不会抛出异常
  • 实现一个非成员swap函数,也就是通过调用成员swap函数,从而确保与std库中的swap函数兼容,使得可以无缝衔接到自己类函数中

5. 尽量延后变量定义的时间

减少性能开销,当定义个类对象的时候,构造函数会立即调用,有可能会涉及到资源分配,所以适当的将变量定义延后,可以避免不必要的初始化

错误分析

例如代码中,即使最终a不是大于b的,变量Result和temp还是被创建了,这就浪费了内存空间

#include <iostream>
#include <string>int main() {int a = 5;int b = 10;int result = 0;  // 提前定义变量std::string temp = "未使用的字符串";  // 提前定义变量if (a > b) {result = a + b;}std::cout << "Result: " << result << std::endl;return 0;
}

解决方法:延后变量的定

也就是说,只有在变量Result和temp需要的时候才被定义,这样就可以避免不必要的内存分配

int main() {int a = 5;int b = 10;if (a > b) {int result = a + b;  // 延后定义变量std::cout << "Result: " << result << std::endl;}if (a == 5) {std::string temp = "延迟定义的字符串";  // 延后定义变量std::cout << "Temp: " << temp << std::endl;}return 0;
}

总结反思

  • 尽量延后变量的定义,减少性能损耗
  • 变量定义在首次使用的地方,可以增强代码可读性

6. 尽量少进行转换

转换增加的劣势

  • 频繁的类型转换会增加代码的复杂程度,使得代码难以理解和维护
  • 运行时的类型转换和多层次的隐式类型转换会损耗性能,最终会拖慢程序的运行速度

隐式类型转换问题分析

  • 代码中如果将double转换成int类型,那么double后面的小数点数据就会丢失

#include <iostream>void printDouble(double value) {std::cout << "Double 值: " << value << std::endl;
}int main() {int intValue = 10;printDouble(intValue);  // 隐式转换 int 到 doubledouble doubleValue = 5.99;int truncatedValue = doubleValue;  // 隐式转换 double 到 intstd::cout << "截断后的 int 值: " << truncatedValue << std::endl;return 0;
}

方法:使用显式类型转换,明确自己想要转换成何种类型

  • 例如可以使用static_cast表明转换意图
#include <iostream>int main() {double doubleValue = 5.99;int truncatedValue = static_cast<int>(doubleValue);  std::cout << "截断后的 int 值: " << truncatedValue << std::endl;return 0;
}

技巧:要避免将基础类型转换为自定义类型的行为

  • 使用explicit关键字避免构造函数进行隐式类型转换,也就是只有在显式声明的时候才可以将double转换为complex对象

  • 隐式类型转换分析
    • Complex c2 = 3.0:double到complex的隐式类型转换
    • 首先explicit关键字的作用就是在一个类中接受单个参数的构造函数,编译器允许使用该函数进行隐式类型转换,所以在这个类中c1对象可以通过传入单个参数完成构造
    • c2报错的原因在于编译器需要从double隐式转换到complex,但是此时构造函数被标记为explicit,所以造成了编译器报错,阻止了这种隐式转换的发生
#include <iostream>class Complex {
public:Complex(double real, double imaginary) : real_(real), imaginary_(imaginary) {}// 避免隐式转换的构造函数explicit Complex(double real) : real_(real), imaginary_(0) {}void print() const {std::cout << "Complex 数: " << real_ << " + " << imaginary_ << "i" << std::endl;}private:double real_;double imaginary_;
};int main() {Complex c1(3.0);  // 合法// Complex c2 = 3.0;  // 编译错误,防止隐式转换c1.print();return 0;
}

总结反思

  • 代码中减少隐式类型转换的使用,从而避免隐式类型转换而导致的错误
  • 多使用显示类型转换,例如可以使用static_cast或者dynamic_cast等,以确保代码意图明确
  • 使用explicit关键字,防止构造函数的隐式类型转换

7. 避免返回对象内部的指针或者引用

直接返回对象的内部指针或者引用会使得对象的实现细节暴露,这样就会导致数据不安全和未定义的行为,特别是当返回指针或者引用是一个局部变量的时候,如果无意中修改了类中的数据,这样就可能会导致问题。

错误分析:返回对象的内部指针或者引用

  • getName函数返回了name_指针,暴露了Person类中的细节
  • 外部可以通过namePtr直接访问或者间接修改Person类的私有数据,最终破坏其封装性

#include <iostream>
#include <string>class Person {
public:Person(const std::string& name) : name_(name) {}// 返回内部指针(不安全)const std::string* getName() const {return &name_;}private:std::string name_;
};int main() {Person p("Alice");const std::string* namePtr = p.getName();std::cout << *namePtr << std::endl;  // 输出:Alice// 非法操作:尽管是 const,外部代码可以修改底层数据或产生悬空指针风险return 0;
}

解决方法:返回name数据的副本,保证不对原始对象的影响

#include <iostream>
#include <string>class Person {
public:Person(const std::string& name) : name_(name) {}// 返回副本std::string getName() const {return name_;}private:std::string name_;
};int main() {Person p("Alice");std::string name = p.getName();std::cout << name << std::endl; // 修改 name 的副本不会影响 Person 对象的 name_name = "Bob";std::cout << p.getName() << std::endl; return 0;
}

返回指针或者引用保证安全方法:使用const限制修改

通过返回数据引用,从而使得const从而确保调用者无法修改返回的内容


#include <iostream>
#include <string>class Person {
public:Person(const std::string& name) : name_(name) {}// 返回 const 引用,防止修改const std::string& getName() const {return name_;}private:std::string name_;
};int main() {Person p("Alice");const std::string& nameRef = p.getName();std::cout << nameRef << std::endl; nameRef = "Bob"; return 0;
}

 使用智能指针安全的返回指针和引用

针对于动态资源分配,使用智能指针可以更好的管理资源分配

  • 通过智能指针管理动态分配的资源,同时通过const限制修改权限
#include <iostream>
#include <memory>
#include <string>class Person {
public:Person(const std::string& name) : name_(std::make_shared<std::string>(name)) {}// 返回智能指针std::shared_ptr<const std::string> getName() const {return name_;}private:std::shared_ptr<const std::string> name_;
};int main() {Person p("Alice");std::shared_ptr<const std::string> namePtr = p.getName();std::cout << *namePtr << std::endl;  // 输出:Alice// *namePtr = "Bob";  // 编译错误,无法修改return 0;
}

总结反思

  •  要避免返回内部数据的指针或引用,尽量选择返回数据的副本,从而保证类的封装性和安全性
  • 如果必须返回引用或者指针,那么使用const限制访问权限,防止其调用修改内部数据
  • 如果是动态资源,需要分配内存空间,那么优先使用智能指针对资源进行管理,从而避免内存泄漏或者悬空指针的情况

8. 为“异常安全”努力

核心意思就是实现在抛出异常的时候保证程序运行安全,也就是在抛出异常的时候要确保状态的完整性和一致性

异常安全的三种保护标准

  • 基本保证:也就是即使发生异常,程序不会发生资源泄漏或者数据不会发生资源泄漏或者数据损坏,即使程序在异常发生后不能恢复正常操作
  • 强烈保证:要求程序在异常后可以退回到异常发生前的状态,也就是操作要么成功要么完全失败,类似于数据库中的原子性
  • 不抛出异常安全保证:承诺某个函数绝对不会抛出异常,也是最强的安全保证,可以通过noexcept关键字声明不抛出异常的函数

方法1:使用RAII

通过RAII机制,保证即使发生异常的时候,也可以保证资源正常释放

#include <iostream>
#include <memory>
#include <string>class Person {
public:Person(const std::string& name) : name_(std::make_unique<std::string>(name)){}void printName() const {std::cout << "姓名: " << *name_ << std::endl;}private:std::unique_ptr<std::string> name_;
};int main() {try {Person p("Alice");p.printName();}catch (...) {std::cout << "异常发生" << std::endl;}return 0;
}

方法2:使用noexcept保证不抛出异常

利用该关键字声明一个函数不会抛出异常,通过noexcept提高代码的稳定性和性能

  • swap函数使用noexcept声明不抛出异常,从而保证swap操作异常的安全性
#include <iostream>
#include <utility>
#include <vector>class Widget {
public:Widget(int value) : value_(value) {}void swap(Widget& other) noexcept {std::swap(value_, other.value_);}private:int value_;
};int main() {Widget w1(1);Widget w2(2);w1.swap(w2);  // 不抛出异常的 swap 操作return 0;
}

方法3:使用事务式编程 

也就是进行操作之前,先创建一个副本或者备份,目的就是确保操作成功后替换原始对象,这样即使操作过程中发生异常的时候,程序依然可以恢复原状

class Transaction {
public:Transaction(const std::string& data) : data_(data) {}void setData(const std::string& newData) {// 先创建备份,保证操作失败时能够恢复std::string backup = data_;// 假设此操作可能抛出异常processData(newData);// 更新成功才替换原数据data_ = newData;}void printData() const {std::cout << "数据: " << data_ << std::endl;}private:void processData(const std::string& newData) {if (newData.empty()) throw std::runtime_error("无效的数据");}std::string data_;
};int main() {Transaction transaction("初始数据");try {transaction.setData("");}catch (const std::exception& e) {std::cout << "异常: " << e.what() << std::endl;}transaction.printData();  // 输出:新数据或初始数据return 0;
}

总结反思

  • 优先使用智能指针管理动态内存资源,从而减少资源泄漏的风险
  • 优先使用noexcept,可以避免其抛出异常
  • 要谨慎操作状态修改,使用备份或者事务机制,从而确保即使发生异常也可以回滚

9. 理解Inline函数的利弊

内联函数就是将函数代码直接嵌入到调用点,从而避免函数调用的开销,编译器会在调用点替换函数调用为函数体代码,这样就减少了调用堆栈的实践。

内联函数的优点分析

  • 减少函数调用时的开销
    • 因为调用函数的时候,程序会进行一系列的操作,例如压栈、跳转到函数地址、返回值处理等,这些都会增加函数的开销
  • 提高性能
    • 对于一些小型、频繁调用的函数使用内联函数可以显著的提高性能
class Rectangle {
public:Rectangle(int width, int height) : width_(width), height_(height) {}// 内联 getter 函数inline int getWidth() const { return width_; }inline int getHeight() const { return height_; }private:int width_;int height_;
};int main() {Rectangle rect(10, 20);int area = rect.getWidth() * rect.getHeight();  // 内联后无调用开销return 0;
}

内联函数的缺点

  • 增加代码体积
    • 内联函数会显著增加代码的体积,也就会导致指令缓存压力增加,最终降低性能
  • 编译时间加长
    • 内联增加了编译器的负担,特别是当函数定义在头文件中时,每次编译都会将函数体嵌入每个调用点,导致编译时间变长,且链接时间也可能增加
  • 内联函数多不方便进行调试

内联函数适用的场景

小型而且简单函数,因为这样的函数逻辑简单,编译器更好对其进行优化;对于一些执行频繁而且对性能要求高的小函数,内联函数也可以显著的提高其性能。

不适合内联函数分析

  • 复杂大型的函数
  • 递归函数
    • 因为递归的调用次数在编译期间是未知的,递归的内联会导致代码膨胀
  • 虚函数
    • 调用的时候需要通过虚函数表进行解析,编译器通常无法再编译期间确定调用的具体函数

总结反思

  • 小函数适合使用内联,相反大且复杂的函数不适合内联
  • 递归和虚函数不适合内联,因为递归次数是不确定,且虚函数通常需要通过表去查找,内联通常会被编译器忽略
  • 编译器自动优化,编译器会自动识别哪些函数适合内联

10. 将文件间的编译依赖降到最低

文件之间编译过度依赖代价

  • 增加编译时间
    • 因为每次修改头文件,或者所有直接或间接依赖该头文件的文件都需要重新编译,这可能导致整个项目的编译时间显著增加。随着项目规模增长,频繁的头文件依赖会拖慢编译速度
  • 耦合度增加
    • 修改一个文件,会影响其他所有与之相关的文件
  • 代码难以维护

方法1:使用前置声明

头文件中尽量使用前置声明,而不是选择包含完整的头文件,使用前置声明一个类的存在,而不需要包含其完整定义,从而减少头文件之间的依赖关系

  • 前置声明适用于指针或者引用成员变量的声明
// Employee.h
#include <string>class Department;  // 前向声明 Department 类class Employee {
public:Employee(const std::string& name);void setDepartment(Department* dept);  // 使用前向声明的指针
private:std::string name_;Department* department_;
};
// Department.h
#include <string>class Department {
public:Department(const std::string& name);
private:std::string name_;
};

方法2:使用#include在源文件中实现依赖

也就是说将头文件的依赖放在源文件中,而不是头文件中,这样就可以减少头文件的包含。只有在类的成员函数需要某个类的定义时,才在.cpp文件中使用#include所需头文件即可

// Employee.h (头文件中只放前置声明)
#include <string>class Department;  // 使用前向声明class Employee {
public:Employee(const std::string& name);void setDepartment(Department* dept);
private:std::string name_;Department* department_;
};
// Employee.cpp
#include "Employee.h"
#include "Department.h"  // 只在 .cpp 文件中包含Employee::Employee(const std::string& name) : name_(name), department_(nullptr) {}void Employee::setDepartment(Department* dept) {department_ = dept;
}

方法3:pimpl方法

在类中使用指针指向该类的方法,将类的实现细节隐藏在源文件中,从而降低头文件的依赖关系;简单可以理解成调用的时候,直接通知封装好的指针

// Widget.h
#include <memory>
class WidgetImpl;  // 前向声明 WidgetImpl 类class Widget {
public:Widget();~Widget();void doSomething();private:std::unique_ptr<WidgetImpl> pImpl;  // Pimpl 指针
};
// Widget.cpp
#include "Widget.h"
#include "WidgetImpl.h"  // 只有在实现文件中包含实现类Widget::Widget() : pImpl(std::make_unique<WidgetImpl>()) {}Widget::~Widget() = default;void Widget::doSomething() {pImpl->performTask();
}

总结反思

  • 头文件使用前向声明,减少对编译的依赖
  • 尽量在.cpp文件中使用#include,而不是头文件
  • pimpl收发,通过指针调用,隐藏细节

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com