精华内容
下载资源
问答
  • 类的声明
    千次阅读
    2019-07-19 18:47:40

    转载自http://www.cnblogs.com/staring-hxs/p/3244251.html

    在编写C++程序的时候,偶尔需要用到前置声明(Forward declaration)。下面的程序中,带注释的那行就是类B的前置说明。这是必须的,因为类A中用到了类B,而类B的声明出现在类A的后面。如果没有类B的前置说明,下面的程序将不同通过编译,编译器将会给出类似“缺少类型说明符”这样的出错提示。

    代码一:
    
    // ForwardDeclaration.h
    #include <iostream>
    using namespace std;
    class B;             // 这是前置声明(Forward declaration)
    class A
    {
    private:
             B* b;
    public:
             A(B* b):b(b){}
    };
    
    class B
    {
    };
    
    // Main.cpp
    #include "ForwardDeclaration.h"
    int main(int argc, char** argv)
    {
             B* b = new B();
             A* a = new A(b);
             delete a;
             delete b;
             return 0;
    }

    上面程序可以顺利编译和运行(几乎没有做什么,也没有输出)。

    是不是有了前置说明就万事大吉了呢?我们看看下面的代码(带阴影部分的代码是新增加的):

    代码二:
    
    
    // ForwardDeclaration.h
    #include <iostream>
    using namespace std;
    class B;             // 这是前置声明(Forward declaration)
    class A
    {
    private:
             B* b;
    public:
             A(B* b):b(b){}
            void someMethod()
             {
                b->someMethod();                                                  // (1)
             }
    };
    
    class B
    {
    public:
          void someMethod()
           {
              cout << "something happened..." << endl;
           }
    };
    // Main.cpp
    #include "ForwardDeclaration.h"
    int main(int argc, char** argv)
    {
             B* b = new B();
             A* a = new A(b);
        a->someMethod();
        delete a;
        delete b;
        return 0;
    }

    一编译,发现代码(1)处出错。出错提示往往包括(不同的编译器给出的提示会有所不同):

    1. 使用了未定义的类型B;

    2. “->somemethod”的左边必须指向类/结构/联合/泛型类型

    原因:

    1. (1)处使用了类型B的定义,因为调用了类B中的一个成员函数。前置声明class B;仅仅声明了有一个B这样的类型,而并没有给出相关的定义,类B的相关定义,是在类A后面出现的,因此出现了编译错误;

    2. 代码一之所以能够通过编译,是因为其中仅仅用到B这个类型,并没有用到类B的定义。

    解决办法是什么?

    将类的声明和类的实现(即类的定义)分离。如下所示:

    // ForwardDeclaration.h   类的声明
    #include <iostream>
    using namespace std;
    class B;             // 这是前置声明(Forward declaration)
    class A
    {
    private:
             B* b;
    public:
            A(B* b);
    void someMethod();
    };
    
    class B
    {
    public:
    void someMethod();
    };
    // ForwardDeclaration.cpp        类的实现
    #include "ForwardDeclaration.h"
    A::A(B* b):b(b)
    {
    
    }
    
    void A::someMethod()
    {
        b->someMethod();
    }
    
    void B::someMethod()
    {
        cout << "something happened..." << endl;
    }
    // Main.cpp
    #include "ForwardDeclaration.h"
    int main(int argc, char** argv)
    {
             B* b = new B();
             A* a = new A(b);
             a->someMethod();
         delete a;
             delete b;
         return 0;
    }

    结论:

    前置声明只能作为指针或引用,不能定义类的对象,自然也就不能调用对象中的方法了。

    而且需要注意,如果将类A的成员变量B* b;改写成B& b;的话,必须要将b在A类的构造函数中,采用初始化列表的方式初始化,否则也会出错。关于这点

    更多相关内容
  • 命名空间是一个范畴,它包含类声明,函数声明,常量声明和模板声明等名字空间成员。本文拟讨论如何在名字空间中声明自己的类和函数,以及如何在程序中使用它们。 在使用C++类时,如果用到命名空间,在使用的时候需要...


    定义

    命名空间是一个范畴,它包含类声明,函数声明,常量声明和模板声明等名字空间成员。本文拟讨论如何在名字空间中声明自己的类和函数,以及如何在程序中使用它们。例如:

    namespace proj_alpha
    {
    //下面是命名空间 proj_alpha 的成员
    class Spy {/*..*/};
    void encrypt (char *msg);
    const int MAX_SPIES = 8;
    }
    

    类声明

    在使用C++类的时候,常常会用到命名空间,在使用的时候一般需要前置声明。例如:

    //SpaceA header file
    #pragma once
    namespace TestA {
    	class SpaceA {
    	public:
    		SpaceA();
    		~SpaceA();
    
    		void print();
    	};
    }
    
    //SpaceA cpp file
    #include "SpaceA.h"
    using namespace TestA; //必须有前置声明
    
    SpaceA::SpaceA() {
    }
    SpaceA::~SpaceA() {
    }
    void SpaceA::print() {
    	int i = 0;
    	i++;
    }
    

    如果命名空间定义的类成员中包含其他命名空间的类,使用的时候,必须加上命名空间。例如:

    //SpaceB header file
    #pragma once
    
    //在使用之前声明一下
    namespace TestA {
    	class SpaceA;
    }
    
    namespace TestB {
    	class SpaceB {
    	public:
    		SpaceB();
    		~SpaceB();
    		void printB();
    	private:
    		TestA::SpaceA* a;//使用的时候,必须加上命名空间
    	};
    } 
    
    //SpaceB cpp file
    #include "SpaceB.h"
    #include "SpaceA.h"
    using namespace TestB;
    using namespace TestA;
    
    SpaceB::SpaceB() {
    	a = new SpaceA;
    }
    
    SpaceB::~SpaceB() {
    }
    
    void SpaceB::printB() {
    	int i = 9;
    	i++;
    	a->print();
    }
    

    主函数中定义方式:

    #include "SpaceB.h"
    using namespace TestB;
    
    int main(int argc, char *argv[]){
    
    	SpaceB b;
    	b.printB();
    }
    

    函数模板

    命名空间中定义函数模板,实例如下:

    //compare header file
    namespace compare{
    	template<class T> T max(const T* data,int size){
    		T result =data[0];
    		for(int i=1;i<size;i++)
    			if(result<data[i])
    				result=data[i];
    			return result;
    	}
    	template <class T> T min(const T* data,int size){
    		T result =data[0];
    		for(int i=1;i<size;i++)
    			if(result>data[i])
    				result=data[i];
    			return result;
    	}
    }
    

    主函数调用方式:

    #include <iostream>
    #include "compare.h"
    using compare::max;
    using compare::min;
    //可以用下面指令的代替上面的声明
    //	using namespace compare;
    using std::cout;
    using std::endl;
     
    int main(){
    	double data[]={1.2,3.3,5.4,2.6,4.7,6.8};
    	const int dataSize=sizeof data/sizeof data[0];
    	cout <<"Min double is "<<min(data ,dataSize)<<endl;
    	cout<<"Max double is "<<max(data,dataSize)<<endl;
    	return 0;
    }
    

    参考文章

    本文参考了如下几篇文章:
    C++在命名空间中声明类和成员函数
    C++在命名空间中使用函数模板
    带有命名空间的C++类的前置声明

    展开全文
  • c++模板类声明和定义的问题

    千次阅读 2019-08-18 21:38:39
    这里在学习的过程中遇到的一些问题,比较简单,但还是记下来,以免下次遇到这个问题再犯,大佬们可跳过哦。先简单的介绍下模板的概念 C++模板(泛型编程) c++模板是泛型编程的基础,所谓...模板模板的概念 一个...

    这里在学习的过程中遇到的一些问题,比较简单,但还是记下来,以免下次遇到这个问题再犯,大佬们可跳过哦。先简单的介绍下模板的概念

    C++模板(泛型编程)

    c++模板是泛型编程的基础,所谓泛型编程也是一种思想,一种抽象数据类型,但是泛型是不属于面向对象,它是面向对象的补充和发展。使用泛型编程简单来说就是能让你把一些相同的代码用指定的去替换它,算是程序员找到的一个偷懒的方法吧。

    模板类和类模板的概念

    一个类模板(类生成类)允许用户为类定义个一种模式,使得类中的某些数据成员、默认成员函数的参数,某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。

    如果一个类中的数据成员的数据类型不能确定,或者是某个成员函数的参数或返回值的类型不能确定,就必须将此类声明为模板,它的存在不是代表一个具体的、实际的类,而是代表一类类。

    类模板定义格式:

    template<typename T>    //这里的typename也可写成class,是一样的,class是之前程序员们所写的一种方式
    class Test
    {
    private:
    	T n;
    	const T i;
    public:
    	Test():i(0){}
    	Test(T k);
    	~Test(){}
    public:
    	void print();
    	T operator+(T x);
    }
    

    如果是在类外定义成员函数,且这个成员函数中有模板参数存在,那么除了和一般类的类外定义成员函数一样定义,还需要在函数外进行模板声明
    例:

    template<typename T>
    void Test<T>::print()
    {
    	cout<<"n="<<n<<endl;   //这里在上面已经添加了iostream
    	cout<<"i="<<i<<endl;
    }
    
    template<typename T>
    Test<T>::Test(T k):i(k)    //这里是初始化列表
    :i(k)
    {
    		n = k;
    }
    template<typename T>
    T Test<T>::operator+(T x)
    {
    	return n+x;
    }
    

    好了,概念抛个差不多就行了,现在开始抛问题,上图
    这种问题呢对于小白来说应该是比较容易犯的一个错误,当你看见语法错误,缺少分号的时候,你肯定会到编辑器报的错误的地方认真仔细的看一遍(这里假想情况是模板类声明和实现分开写的),没毛病呀,于是又仔细的看一遍,还是找不到错误的地方。好了,这种情况实际上是因为前面写类的时候后面忘了添加分号的原因哦,所以请到.h文件中查看类的后面是不是少写了一个分号吧。
    对于这种出现大量函数模板已经定义的情况,很大情况是由于头文件冲突所导致的,如果你是.h和.cpp分开写的话,可以在.h的类后面加上#include xxx.cpp,其中的内容是你写的类名,这种写法呢其实就相当于把声明和实现写在了一个文件里。这里要注意在.cpp文件里面不要包含当前类的.h文件哦,不要包含,不要包含,不要包含!当然你还有可能出现命名冲突的情况,那么你可以在.h文件中头部添加#infdef XXXX_H,#define XXXX_H,这里写你的文件名,然后尾部再写上#endif。如果你遇到了非常糟糕的情况:error LNK2019:无法解析的外部符号的情况,后面跟着名称粉碎,那还是再看看头文件吧。

    好了,说的这些应该是非常基础的一些知识了,好吧,对于大佬来说肯定会有鄙视的眼神的,这些都是常识。唔,好吧,大佬说的都是对的。第一次写博客,写的非常的简陋,今后有时间的话争取把内容再扩充扩充吧。

    展开全文
  • C++模板类声明和定义几种写法

    万次阅读 2018-11-29 01:01:17
    为什么模板的实现放在cpp会出错 在编译用到了模板的编译单元时,编译器需要访问方法或者的实现...声明和定义都放在.h中 // Foo.h template &amp;amp;amp;lt;typename T&amp;amp;amp;gt; struct Foo { ...

    为什么模板类的实现放在cpp会出错

    在编译用到了模板类的编译单元时,编译器需要访问方法或者类的实现,以实例化它们。 如果这些实现不在头文件中,则它们将不可访问,因此编译器将无法实例化模板,进而会导致编译出错。

    模板类的定义必须放在.h文件中吗

    答案是否定的,模板类的几种写法

    声明和定义都放在.h中

    // Foo.h
    template <typename T>
    struct Foo
    {
        void doSomething(T param) {}
    };
    

    声明和定义分隔开

    // Foo.h
    template <typename T>
    struct Foo
    {
        void doSomething(T param);
    };
    
    #include "Foo.tpp"
    
    // Foo.tpp
    template <typename T>
    void Foo<T>::doSomething(T param)
    {
        //implementation
    }
    

    实现放在了Foo.tpp,然而还是include Foo.tpp在了头文件中,只是做了文件的分隔,但是其他文件include了头文件后,还是把实现也包含进去了,跟都放在.h效果类似,只是实现和声明分开,代码可读性更好

    声明放在.h文件,定义放在.cpp文件

    // Foo.h
    // no implementation
    template <typename T> struct Foo { ... };
    
    //----------------------------------------    
    
    // Foo.cpp
    // implementation of Foo's methods
    
    // explicit instantiations
    template class Foo<int>;
    template class Foo<float>;
    // You will only be able to use Foo with int or float
    

    正在的声明和实现分离,include了头文件之后不会把实现的代码也加入到该编译单元。然后需要将所有用到的类型都显式的实例化

    什么是实例化

    编译器怎么处理模板呢?本质上来说,模板可被编译器产生多种多样函数和类的代码。只有当被使用的时候,编译器才会产生用于这种类型的代码。模板不是直接编译成以后需要的各种类的实现,而是将模板代码解析放入内存中,当编译某个编译单元需要用到该模板,则会按需产生相应的代码。实例化是编译器确定特定模板与特定参数集一起使用并在模板上执行参数替换以生成要编译的类或函数以及最终编译为模板的二进制代码的过程。

    有两种类型模板实例化,隐式和显式。
    显式的实例化见第三段代码,Foo.cpp中显式实例化了Foo和Foo。显式实例化会实例化所有的成员函数。
    隐式实例化是一种按需实例化。当你使用一个模板类时,编译器才会进行实例化。例如如果你使用vector,此时编译器才会创建一个vector类型,并且只会实例化所需要的函数。不实例化所有的成员函数主要有两点原因:
    1、节省编译时间
    2、不同的成员函数对类型属性有一些要求,不实例化可以使得更多的类型可以用到模板类。例如map的operator[]操作符要求value是有默认构造函数的,因为你通过不存在的key访问value的时候会新建一个value,且是需要调用默认构造函数。如果你不需要这个操作,用find和insert也可以达到目标,这样对value的类型就少了一个限制,使得模板类更具有普适性。

    特化template时遇到的duplicate symbol问题

    stackoverflow上面有案例,详见multiple definition of template specialization when using different objects

    Intuitively, when you fully specialize something, it doesn’t depend on a template parameter any more – so unless you make the specialization inline, you need to put it in a .cpp file instead of a .h or you end up violating the one definition rule as David says. Note that when you partially specialize templates, the partial specializations do still depend on one or more template parameters, so they still go in a .h file.

    翻译过来:
    直观地说,当你完全特化某些东西时,它不再依赖于模板参数,所以除非你使内联专业化,你需要将它放在.cpp文件中而不是.h中,否则你最终会违反大卫说的一个定义规则。 请注意,当您对模板进行部分特化时,部分特化仍然依赖于一个或多个模板参数,因此它们仍然位于.h文件中。
    推荐的写法为:
    举例,template中static成员的初始化,完全特化实现在.cpp中

    template<> int B<A, 1>::a[1] = { };
    

    声明在.h中

    template<> int B<A, 1>::a[1];
    

    详见static member initialization for specialized template class

    参考文档

    Why can templates only be implemented in the header file?
    Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
    c++ 模板类 声明和定义都放在.h文件的原因
    Meaning of ‘instantiation’ with respect to templates

    展开全文
  • #include <iostream>...需要对date提前引用声明 class Date; //定义time class Time { public: Time(int, int, int); //成员函数,形参是date的引用 void display(Date&); private: ...
  • 数组和类声明的几种方式

    万次阅读 2018-07-04 18:10:49
    //数组的声明 //第一种 int[] arr1 = null; arr1 = new int[3]; //第二种 int[] arr2 = new int[3]; //第三种 int[] arr3 = ne...
  • 习题 9.11 将例9.13中的Time类声明为Date类的友元类,通过Time类中的display函数引用Date类对象的私有数据,输出年、月、日和时、分、秒。 代码块: #include &lt;iostream&gt; using namespace std; ...
  • c++友元类声明及其调用

    千次阅读 2017-09-26 11:19:28
    c++友元的相关理解及定义使用!!!
  • JAVA 类声明中关键字public的作用

    万次阅读 多人点赞 2017-11-25 22:10:04
    使用public关键字声明必须与java文件名保持一致,并且一个java文件中只能有一个public关键字修饰的名称,编译后会产生一个与java文件名 相应的.class文件,而一个java文件中可以同时又多个不使用public关键字...
  • Java之路:声明与定义

    万次阅读 多人点赞 2018-12-03 21:01:15
    类声明的语法如下: [标识符] class 类名称 { //类的成员变量 //类的方法 } 在上面的语法格式中,[标识符] 可以是public、private、protected或者完全省略这个修饰符。 类名称遵循标识符命名规则与规范,这里...
  • Python——声明与定义

    千次阅读 2021-05-22 14:37:43
    声明与定义 Python 是一门面向对象的语言。面向对象编程 - Object Oriented Programming(简称 OOP)是一种编程思想,在面向对象编程中,把对象作为程序的基本单元,把程序视为一系列对象的集合。一个对象包括...
  • 原文:... 为了理解static关键字在类声明中的使用,首先我们需要了解类声明。有两种类,一种是top-level class;一种是inner class。 Top-level class
  • (二)C++头文件与声明

    千次阅读 2022-04-15 21:28:07
    了解C++中一个基本的头文件,和主文件中使用的声明具体格式。对头文件进行格式说明和讲解。
  • #include using namespace std; class Time; class Date {public: Date(int,int,int); friend Time; private: int month; int day;...Date::Date(int m,int d,int y):month(m),day(d),year(y){ } class
  • Python类声明私有变量和私有方法

    千次阅读 2018-11-10 11:47:53
    Python类声明私有变量和私有方法 类的私有变量和私有方法 在Python中可以通过在属性变量名前加上双下划线定义属性为private;添加_变成protected. 语法规则:特殊变量命名 _xx 以单下划线开头的表示的是protected...
  • C++中的——的定义和声明

    万次阅读 多人点赞 2018-08-23 10:49:04
    在以面向对象的方式开发应用程序时,将遇到的各种事物抽象为中通常包含数据和操作数据的方法,用户通过实例化对象来访问中的数据和方法。 一、的定义 class/struct 类名 //头 {数据和方法的定义...
  • Java声明详解

    万次阅读 多人点赞 2018-06-20 17:50:20
    本篇博客为原创博客,转载请注明出处!有什么不对或去需要改进的地方,请指出。...二、类声明语法 [修饰符] [static] [final] [abstract] [strictfp] class 类名 [extends 父类名] [implements 接口名] { ...
  • 不完整的类声明(incomplete class declarations ) 问题 和 解答   两个类放入一个文件时, 如果包含内联函数, 及友元(friend)类, 则函数放置的顺序尤为重要, 类的前置声明(class forward declaration)也需要注意. ...
  • 友元提供了不同的成员函数之间、的成员函数与一般函数之间进行数据共享的机制。通过友元,一个不同函数或另一个中的成员函数可以访问中的私有成员和保护成员。c++中的友元为封装隐藏这堵不透明的墙开了一个...
  • 类声明和成员函数定义的分离

    千次阅读 2015-10-12 21:06:59
    为了实现类的隐蔽性,对类成员函数的定义一般不放在头文件中,而放在另一个文件中,即类声明和函数定义是分别放在两个文件中的。 实际上一个C++程序是由3个部分组成的:类声明头文件(后缀为.h);类实现文件(后缀...
  • 抽象声明

    千次阅读 2018-06-07 01:10:34
    抽象不可以实例化但是可以通过下列两种方法声明:1、父类类型的引用指向子类的对象; 2、 接口类型的引用指向该接口的实现的对象; 以上两种使用方式也就是所谓的“向上转型”。...
  • c++ 的定义与声明

    万次阅读 2017-08-04 15:40:08
     通常我们会在cpp文件中,完成函数的实现,在h文件中进行函数的声明。在引用时,我们只要包含其头文件即可,便可以调用相应cpp中的实现函数。因此,在实现文件cpp中,我们必须包含定义该的头文件。
  • c++中声明和实现

    千次阅读 2019-11-08 18:59:16
    (1) 当c++中声明和实现放在一个中时,c++编译器会把函数当成内联函数来对待,如下面的getR函数,c++编译器就会把其当成一个内联函数。 class Circle { public: double r; double s; public: double get...
  • C++声明和定义

    千次阅读 2019-05-20 12:10:13
    这里将采取比较规整的方式来解决这个的构建问题。 // Date.h #include <iostream> using namespace std; class Date { public: Date(); //这是默认的构造函数 //如果有兴趣的话,可以理解下,...
  • Java的定义、声明及使用

    千次阅读 2020-03-01 23:15:22
    一、声明 在使用前,必须先声明,然后才可以声明变量,创建对象。 声明语法如下: [标识符] class 类名{ //的属性 //的方法 } 名称遵循标识符命名规则与规范,这里不做详细讲解,有兴趣的...
  • C++的定义和声明怎么写

    千次阅读 2019-01-08 17:42:59
    C++语言可以看成是C语言的扩展和改进,相对于C语言,C++语言主要是增添了面向对象的特性。(Class)则是C++面向对象编程的实现方式。 无论是何种编程语言,进行面向...首先我们来了解一下声明,先来看一个例子...
  • cpp————声明 定义 实现

    千次阅读 2017-02-10 15:56:13
    声明,又称的前向声明,即forward declaration,告诉编译器class类型,但当前并不知道class具体细节,是不完全类型 声明只能用于指针(引用)类型,因为指针(引用)类型字长固定,编译器知道分配多少内存空间...
  • 1.声明和实现为什么要分开写 现在开始写项目了,你会发现我们一般都要写一个cpp,对应的还得有一个h文件,那么为什么在C++中我们要这么做? .h就是声明,.cpp就是实现,而所谓分离式实现就是指“声明”和“定义”...
  • C++学习:内部声明和定义

    千次阅读 2017-07-02 17:14:35
    C++学习:内部声明和定义简介: 内部也就是内部的,是包含在一个里面的 注意: 此时这个不属于外部的,不能通过外部的对象直接调用内部,外部的对内部的没有任何优越的访问权限提示: 博主:...
  • c++中模板_模板的声明和定义

    千次阅读 2017-11-17 11:24:18
    一、函数模板用法 1.1申明和定义 Ø 在函数申明和定义前面,加一个模板...Ø 模板的声明或定义只能在全局,命名空间或范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板 1....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,126,508
精华内容 850,603
关键字:

类的声明

友情链接: 第一程序4800.zip